From 60fe4620ff2b837f25525000b78061b608e3b193 Mon Sep 17 00:00:00 2001 From: devbeni Date: Mon, 16 Jun 2025 13:12:58 +0000 Subject: [PATCH 1/2] Initial commit --- LICENSE | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 2 files changed, 237 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1ce809a --- /dev/null +++ b/LICENSE @@ -0,0 +1,235 @@ +GNU AFFERO GENERAL PUBLIC LICENSE +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + + Preamble + +The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. + +A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. + +The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. + +An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. + +The precise terms and conditions for copying, distribution and modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the Program. + +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. +The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". + + c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + +6. Conveying Non-Source Forms. +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + + a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. + + d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + +7. Additional Terms. +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or authors of the material; or + + e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. + +All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + survival-game + Copyright (C) 2025 devbeni + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf91e3d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# survival-game + -- 2.34.1 From 074e590073664287c8711a1940960b25d40ed6cb Mon Sep 17 00:00:00 2001 From: B3ni Date: Mon, 16 Jun 2025 15:14:23 +0200 Subject: [PATCH 2/2] aha --- .gitignore | 61 + .plastic/plastic.changes | Bin 0 -> 462290 bytes .plastic/plastic.selector | 4 + .plastic/plastic.wktree | Bin 0 -> 474396 bytes .plastic/plastic.workspace | 2 + Assets/InputSystem_Actions.inputactions | 1057 ++ Assets/InputSystem_Actions.inputactions.meta | 14 + Assets/Materials.meta | 8 + Assets/Materials/CloudMat.mat | 136 + Assets/Materials/CloudMat.mat.meta | 8 + Assets/Materials/DemoPlaneMat.mat | 138 + Assets/Materials/DemoPlaneMat.mat.meta | 15 + Assets/Materials/EmissionBlueMat.mat | 139 + Assets/Materials/EmissionBlueMat.mat.meta | 15 + Assets/Materials/EmissionYellowMat.mat | 139 + Assets/Materials/EmissionYellowMat.mat.meta | 15 + Assets/Materials/Flower1.mat | 136 + Assets/Materials/Flower1.mat.meta | 8 + Assets/Materials/Flower2Mat.mat | 138 + Assets/Materials/Flower2Mat.mat.meta | 15 + Assets/Materials/Flower3Mat.mat | 138 + Assets/Materials/Flower3Mat.mat.meta | 15 + Assets/Materials/Flower4Mat.mat | 138 + Assets/Materials/Flower4Mat.mat.meta | 15 + Assets/Materials/Mushroom1Mat.mat | 138 + Assets/Materials/Mushroom1Mat.mat.meta | 15 + Assets/Materials/Mushroom2Mat.mat | 138 + Assets/Materials/Mushroom2Mat.mat.meta | 15 + Assets/Materials/Mushroom3Mat.mat | 138 + Assets/Materials/Mushroom3Mat.mat.meta | 15 + Assets/Materials/PlantMat.mat | 138 + Assets/Materials/PlantMat.mat.meta | 15 + Assets/Materials/RockMat.mat | 138 + Assets/Materials/RockMat.mat.meta | 15 + Assets/Materials/TreeGreen1Mat.mat | 138 + Assets/Materials/TreeGreen1Mat.mat.meta | 15 + Assets/Materials/TreeGreen2Mat.mat | 138 + Assets/Materials/TreeGreen2Mat.mat.meta | 15 + Assets/Materials/TreeOrangeMat.mat | 138 + Assets/Materials/TreeOrangeMat.mat.meta | 15 + Assets/Materials/TreePinkMat.mat | 138 + Assets/Materials/TreePinkMat.mat.meta | 15 + Assets/Materials/TreeRedMat.mat | 138 + Assets/Materials/TreeRedMat.mat.meta | 15 + Assets/Materials/TreeYellowMat.mat | 138 + Assets/Materials/TreeYellowMat.mat.meta | 15 + Assets/Materials/Wood1Mat.mat | 138 + Assets/Materials/Wood1Mat.mat.meta | 15 + Assets/Materials/Wood2Mat.mat | 138 + Assets/Materials/Wood2Mat.mat.meta | 15 + Assets/Mirror.meta | 8 + Assets/Mirror/Authenticators.meta | 8 + .../Authenticators/BasicAuthenticator.cs | 192 + .../Authenticators/BasicAuthenticator.cs.meta | 18 + .../Authenticators/DeviceAuthenticator.cs | 129 + .../DeviceAuthenticator.cs.meta | 18 + .../Mirror.Authenticators.asmdef | 16 + .../Mirror.Authenticators.asmdef.meta | 14 + .../Authenticators/TimeoutAuthenticator.cs | 70 + .../TimeoutAuthenticator.cs.meta | 18 + Assets/Mirror/CompilerSymbols.meta | 8 + .../Mirror.CompilerSymbols.asmdef | 14 + .../Mirror.CompilerSymbols.asmdef.meta | 14 + .../CompilerSymbols/PreprocessorDefine.cs | 45 + .../PreprocessorDefine.cs.meta | 18 + Assets/Mirror/Components.meta | 8 + Assets/Mirror/Components/AssemblyInfo.cs | 12 + Assets/Mirror/Components/AssemblyInfo.cs.meta | 18 + Assets/Mirror/Components/Discovery.meta | 8 + .../Components/Discovery/NetworkDiscovery.cs | 93 + .../Discovery/NetworkDiscovery.cs.meta | 18 + .../Discovery/NetworkDiscoveryBase.cs | 473 + .../Discovery/NetworkDiscoveryBase.cs.meta | 18 + .../Discovery/NetworkDiscoveryHUD.cs | 144 + .../Discovery/NetworkDiscoveryHUD.cs.meta | 18 + .../Components/Discovery/ServerRequest.cs | 4 + .../Discovery/ServerRequest.cs.meta | 18 + .../Components/Discovery/ServerResponse.cs | 18 + .../Discovery/ServerResponse.cs.meta | 18 + Assets/Mirror/Components/GUIConsole.cs | 133 + Assets/Mirror/Components/GUIConsole.cs.meta | 18 + .../Mirror/Components/InterestManagement.meta | 8 + .../InterestManagement/Distance.meta | 3 + .../Distance/DistanceInterestManagement.cs | 89 + .../DistanceInterestManagement.cs.meta | 18 + .../DistanceInterestManagementCustomRange.cs | 15 + ...tanceInterestManagementCustomRange.cs.meta | 18 + .../Components/InterestManagement/Match.meta | 3 + .../Match/MatchInterestManagement.cs | 164 + .../Match/MatchInterestManagement.cs.meta | 18 + .../InterestManagement/Match/NetworkMatch.cs | 42 + .../Match/NetworkMatch.cs.meta | 18 + .../Components/InterestManagement/Scene.meta | 3 + .../Scene/SceneInterestManagement.cs | 117 + .../Scene/SceneInterestManagement.cs.meta | 18 + .../InterestManagement/SceneDistance.meta | 8 + .../SceneDistanceInterestManagement.cs | 178 + .../SceneDistanceInterestManagement.cs.meta | 18 + .../InterestManagement/SpatialHashing.meta | 3 + .../SpatialHashing/Grid2D.cs | 104 + .../SpatialHashing/Grid2D.cs.meta | 18 + .../SpatialHashing/Grid3D.cs | 106 + .../SpatialHashing/Grid3D.cs.meta | 10 + .../SpatialHashing/HexGrid2D.cs | 170 + .../SpatialHashing/HexGrid2D.cs.meta | 18 + .../SpatialHashing/HexGrid3D.cs | 243 + .../SpatialHashing/HexGrid3D.cs.meta | 18 + .../HexSpatialHash2DInterestManagement.cs | 345 + ...HexSpatialHash2DInterestManagement.cs.meta | 18 + .../HexSpatialHash3DInterestManagement.cs | 336 + ...HexSpatialHash3DInterestManagement.cs.meta | 18 + .../SpatialHashing3DInterestManagement.cs | 146 + ...SpatialHashing3DInterestManagement.cs.meta | 18 + .../SpatialHashingInterestManagement.cs | 156 + .../SpatialHashingInterestManagement.cs.meta | 18 + .../Components/InterestManagement/Team.meta | 8 + .../InterestManagement/Team/NetworkTeam.cs | 39 + .../Team/NetworkTeam.cs.meta | 18 + .../Team/TeamInterestManagement.cs | 182 + .../Team/TeamInterestManagement.cs.meta | 18 + Assets/Mirror/Components/LagCompensation.meta | 8 + .../LagCompensation/HistoryCollider.cs | 109 + .../LagCompensation/HistoryCollider.cs.meta | 18 + .../LagCompensation/LagCompensator.cs | 197 + .../LagCompensation/LagCompensator.cs.meta | 18 + .../Components/Mirror.Components.asmdef | 16 + .../Components/Mirror.Components.asmdef.meta | 14 + Assets/Mirror/Components/NetworkAnimator.cs | 662 + .../Mirror/Components/NetworkAnimator.cs.meta | 18 + .../Components/NetworkDiagnosticsDebugger.cs | 31 + .../NetworkDiagnosticsDebugger.cs.meta | 18 + .../Mirror/Components/NetworkLobbyManager.cs | 18 + .../Components/NetworkLobbyManager.cs.meta | 18 + .../Mirror/Components/NetworkLobbyPlayer.cs | 15 + .../Components/NetworkLobbyPlayer.cs.meta | 18 + .../Mirror/Components/NetworkPingDisplay.cs | 39 + .../Components/NetworkPingDisplay.cs.meta | 18 + .../Mirror/Components/NetworkRigidbody.meta | 3 + .../NetworkRigidbodyReliable.cs | 115 + .../NetworkRigidbodyReliable.cs.meta | 18 + .../NetworkRigidbodyReliable2D.cs | 135 + .../NetworkRigidbodyReliable2D.cs.meta | 18 + .../NetworkRigidbodyUnreliable.cs | 115 + .../NetworkRigidbodyUnreliable.cs.meta | 18 + .../NetworkRigidbodyUnreliable2D.cs | 136 + .../NetworkRigidbodyUnreliable2D.cs.meta | 18 + .../Mirror/Components/NetworkRoomManager.cs | 683 + .../Components/NetworkRoomManager.cs.meta | 18 + Assets/Mirror/Components/NetworkRoomPlayer.cs | 195 + .../Components/NetworkRoomPlayer.cs.meta | 18 + Assets/Mirror/Components/NetworkStatistics.cs | 194 + .../Components/NetworkStatistics.cs.meta | 18 + .../Mirror/Components/NetworkTransform.meta | 3 + .../NetworkTransform/NetworkTransformBase.cs | 547 + .../NetworkTransformBase.cs.meta | 18 + .../NetworkTransformHybrid.cs | 717 + .../NetworkTransformHybrid.cs.meta | 18 + .../NetworkTransformReliable.cs | 448 + .../NetworkTransformReliable.cs.meta | 18 + .../NetworkTransformUnreliable.cs | 462 + .../NetworkTransformUnreliable.cs.meta | 18 + .../NetworkTransform/TransformSnapshot.cs | 68 + .../TransformSnapshot.cs.meta | 18 + .../NetworkTransform/TransformSyncData.cs | 156 + .../TransformSyncData.cs.meta | 18 + .../Mirror/Components/PredictedRigidbody.meta | 3 + .../PredictedRigidbody/LocalGhostMaterial.mat | 85 + .../LocalGhostMaterial.mat.meta | 15 + .../PredictedRigidbody/PredictedRigidbody.cs | 1021 ++ .../PredictedRigidbody.cs.meta | 22 + .../PredictedRigidbodyPhysicsGhost.cs | 15 + .../PredictedRigidbodyPhysicsGhost.cs.meta | 18 + .../PredictedRigidbodyRemoteGhost.cs | 1 + .../PredictedRigidbodyRemoteGhost.cs.meta | 18 + .../PredictedRigidbody/PredictedSyncData.cs | 54 + .../PredictedSyncData.cs.meta | 10 + .../PredictedRigidbody/PredictionUtils.cs | 430 + .../PredictionUtils.cs.meta | 18 + .../RemoteGhostMaterial.mat | 85 + .../RemoteGhostMaterial.mat.meta | 15 + .../PredictedRigidbody/RigidbodyState.cs | 60 + .../PredictedRigidbody/RigidbodyState.cs.meta | 18 + Assets/Mirror/Components/Profiling.meta | 3 + .../Components/Profiling/BaseUIGraph.cs | 217 + .../Components/Profiling/BaseUIGraph.cs.meta | 21 + .../Components/Profiling/FpsMinMaxAvgGraph.cs | 40 + .../Profiling/FpsMinMaxAvgGraph.cs.meta | 18 + .../Mirror/Components/Profiling/LineGraph.mat | 89 + .../Components/Profiling/LineGraph.mat.meta | 15 + .../Profiling/NetworkBandwidthGraph.cs | 85 + .../Profiling/NetworkBandwidthGraph.cs.meta | 18 + .../Profiling/NetworkGraphLines.shader | 178 + .../Profiling/NetworkGraphLines.shader.meta | 10 + .../Profiling/NetworkGraphStacked.shader | 138 + .../Profiling/NetworkGraphStacked.shader.meta | 10 + .../Components/Profiling/NetworkPingGraph.cs | 34 + .../Profiling/NetworkPingGraph.cs.meta | 18 + .../Profiling/NetworkRuntimeProfiler.cs | 315 + .../Profiling/NetworkRuntimeProfiler.cs.meta | 18 + .../Mirror/Components/Profiling/Prefabs.meta | 8 + .../Profiling/Prefabs/BandwidthGraph.prefab | 1776 +++ .../Prefabs/BandwidthGraph.prefab.meta | 14 + .../Profiling/Prefabs/FPSMinMaxAvg.prefab | 1976 +++ .../Prefabs/FPSMinMaxAvg.prefab.meta | 14 + .../Profiling/Prefabs/GraphCanvas.prefab | 765 + .../Profiling/Prefabs/GraphCanvas.prefab.meta | 14 + .../Profiling/Prefabs/NetworkGraph.prefab | 2888 ++++ .../Prefabs/NetworkGraph.prefab.meta | 14 + .../Profiling/Prefabs/PingGraph.prefab | 1776 +++ .../Profiling/Prefabs/PingGraph.prefab.meta | 14 + .../Components/Profiling/StackedGraph.mat | 88 + .../Profiling/StackedGraph.mat.meta | 15 + .../Components/Profiling/ToggleHotkey.cs | 15 + .../Components/Profiling/ToggleHotkey.cs.meta | 18 + Assets/Mirror/Components/RemoteStatistics.cs | 441 + .../Components/RemoteStatistics.cs.meta | 18 + Assets/Mirror/Core.meta | 8 + Assets/Mirror/Core/AssemblyInfo.cs | 13 + Assets/Mirror/Core/AssemblyInfo.cs.meta | 18 + Assets/Mirror/Core/Attributes.cs | 101 + Assets/Mirror/Core/Attributes.cs.meta | 18 + Assets/Mirror/Core/Batching.meta | 8 + Assets/Mirror/Core/Batching/Batcher.cs | 206 + Assets/Mirror/Core/Batching/Batcher.cs.meta | 18 + Assets/Mirror/Core/Batching/Unbatcher.cs | 129 + Assets/Mirror/Core/Batching/Unbatcher.cs.meta | 18 + Assets/Mirror/Core/ConnectionQuality.cs | 74 + Assets/Mirror/Core/ConnectionQuality.cs.meta | 18 + Assets/Mirror/Core/HostMode.cs | 44 + Assets/Mirror/Core/HostMode.cs.meta | 18 + Assets/Mirror/Core/InterestManagement.cs | 146 + Assets/Mirror/Core/InterestManagement.cs.meta | 18 + Assets/Mirror/Core/InterestManagementBase.cs | 103 + .../Core/InterestManagementBase.cs.meta | 18 + Assets/Mirror/Core/LagCompensation.meta | 3 + Assets/Mirror/Core/LagCompensation/Capture.cs | 13 + .../Core/LagCompensation/Capture.cs.meta | 18 + .../Core/LagCompensation/HistoryBounds.cs | 139 + .../LagCompensation/HistoryBounds.cs.meta | 18 + .../Core/LagCompensation/LagCompensation.cs | 144 + .../LagCompensation/LagCompensation.cs.meta | 18 + .../LagCompensationSettings.cs | 19 + .../LagCompensationSettings.cs.meta | 18 + .../Core/LagCompensation/MinMaxBounds.cs | 73 + .../Core/LagCompensation/MinMaxBounds.cs.meta | 18 + Assets/Mirror/Core/LocalConnectionToClient.cs | 80 + .../Core/LocalConnectionToClient.cs.meta | 18 + Assets/Mirror/Core/LocalConnectionToServer.cs | 117 + .../Core/LocalConnectionToServer.cs.meta | 18 + Assets/Mirror/Core/Messages.cs | 186 + Assets/Mirror/Core/Messages.cs.meta | 18 + Assets/Mirror/Core/Mirror.asmdef | 16 + Assets/Mirror/Core/Mirror.asmdef.meta | 14 + Assets/Mirror/Core/NetworkAuthenticator.cs | 84 + .../Mirror/Core/NetworkAuthenticator.cs.meta | 18 + Assets/Mirror/Core/NetworkBehaviour.cs | 1386 ++ Assets/Mirror/Core/NetworkBehaviour.cs.meta | 18 + Assets/Mirror/Core/NetworkBehaviourHybrid.cs | 483 + .../Core/NetworkBehaviourHybrid.cs.meta | 18 + Assets/Mirror/Core/NetworkBehaviourSyncVar.cs | 33 + .../Core/NetworkBehaviourSyncVar.cs.meta | 18 + Assets/Mirror/Core/NetworkClient.cs | 1885 +++ Assets/Mirror/Core/NetworkClient.cs.meta | 18 + .../Core/NetworkClient_TimeInterpolation.cs | 151 + .../NetworkClient_TimeInterpolation.cs.meta | 18 + Assets/Mirror/Core/NetworkConnection.cs | 207 + Assets/Mirror/Core/NetworkConnection.cs.meta | 18 + .../Mirror/Core/NetworkConnectionToClient.cs | 230 + .../Core/NetworkConnectionToClient.cs.meta | 18 + .../Mirror/Core/NetworkConnectionToServer.cs | 24 + .../Core/NetworkConnectionToServer.cs.meta | 18 + Assets/Mirror/Core/NetworkDiagnostics.cs | 63 + Assets/Mirror/Core/NetworkDiagnostics.cs.meta | 18 + Assets/Mirror/Core/NetworkIdentity.cs | 1411 ++ Assets/Mirror/Core/NetworkIdentity.cs.meta | 18 + Assets/Mirror/Core/NetworkLoop.cs | 211 + Assets/Mirror/Core/NetworkLoop.cs.meta | 18 + Assets/Mirror/Core/NetworkManager.cs | 1452 ++ Assets/Mirror/Core/NetworkManager.cs.meta | 18 + Assets/Mirror/Core/NetworkManagerHUD.cs | 162 + Assets/Mirror/Core/NetworkManagerHUD.cs.meta | 18 + Assets/Mirror/Core/NetworkMessage.cs | 4 + Assets/Mirror/Core/NetworkMessage.cs.meta | 18 + Assets/Mirror/Core/NetworkMessages.cs | 210 + Assets/Mirror/Core/NetworkMessages.cs.meta | 18 + Assets/Mirror/Core/NetworkReader.cs | 249 + Assets/Mirror/Core/NetworkReader.cs.meta | 18 + Assets/Mirror/Core/NetworkReaderExtensions.cs | 420 + .../Core/NetworkReaderExtensions.cs.meta | 18 + Assets/Mirror/Core/NetworkReaderPool.cs | 48 + Assets/Mirror/Core/NetworkReaderPool.cs.meta | 18 + Assets/Mirror/Core/NetworkReaderPooled.cs | 12 + .../Mirror/Core/NetworkReaderPooled.cs.meta | 18 + Assets/Mirror/Core/NetworkServer.cs | 2111 +++ Assets/Mirror/Core/NetworkServer.cs.meta | 18 + Assets/Mirror/Core/NetworkStartPosition.cs | 21 + .../Mirror/Core/NetworkStartPosition.cs.meta | 18 + Assets/Mirror/Core/NetworkTime.cs | 243 + Assets/Mirror/Core/NetworkTime.cs.meta | 18 + Assets/Mirror/Core/NetworkWriter.cs | 249 + Assets/Mirror/Core/NetworkWriter.cs.meta | 18 + Assets/Mirror/Core/NetworkWriterExtensions.cs | 471 + .../Core/NetworkWriterExtensions.cs.meta | 18 + Assets/Mirror/Core/NetworkWriterPool.cs | 40 + Assets/Mirror/Core/NetworkWriterPool.cs.meta | 18 + Assets/Mirror/Core/NetworkWriterPooled.cs | 10 + .../Mirror/Core/NetworkWriterPooled.cs.meta | 18 + Assets/Mirror/Core/PortTransport.cs | 13 + Assets/Mirror/Core/PortTransport.cs.meta | 18 + Assets/Mirror/Core/Prediction.meta | 3 + Assets/Mirror/Core/Prediction/Prediction.cs | 195 + .../Mirror/Core/Prediction/Prediction.cs.meta | 18 + Assets/Mirror/Core/RemoteCalls.cs | 151 + Assets/Mirror/Core/RemoteCalls.cs.meta | 18 + Assets/Mirror/Core/SnapshotInterpolation.meta | 8 + .../Core/SnapshotInterpolation/Snapshot.cs | 17 + .../SnapshotInterpolation/Snapshot.cs.meta | 18 + .../SnapshotInterpolation.cs | 390 + .../SnapshotInterpolation.cs.meta | 18 + .../SnapshotInterpolationSettings.cs | 70 + .../SnapshotInterpolationSettings.cs.meta | 10 + .../SnapshotInterpolation/TimeSnapshot.cs | 15 + .../TimeSnapshot.cs.meta | 18 + Assets/Mirror/Core/SyncDictionary.cs | 358 + Assets/Mirror/Core/SyncDictionary.cs.meta | 18 + Assets/Mirror/Core/SyncList.cs | 473 + Assets/Mirror/Core/SyncList.cs.meta | 18 + Assets/Mirror/Core/SyncObject.cs | 53 + Assets/Mirror/Core/SyncObject.cs.meta | 18 + Assets/Mirror/Core/SyncSet.cs | 377 + Assets/Mirror/Core/SyncSet.cs.meta | 18 + Assets/Mirror/Core/Threading.meta | 8 + .../Threading/ConcurrentNetworkWriterPool.cs | 45 + .../ConcurrentNetworkWriterPool.cs.meta | 18 + .../ConcurrentNetworkWriterPooled.cs | 10 + .../ConcurrentNetworkWriterPooled.cs.meta | 10 + .../Mirror/Core/Threading/ConcurrentPool.cs | 44 + .../Core/Threading/ConcurrentPool.cs.meta | 18 + Assets/Mirror/Core/Threading/ThreadLog.cs | 112 + .../Mirror/Core/Threading/ThreadLog.cs.meta | 18 + Assets/Mirror/Core/Threading/WorkerThread.cs | 169 + .../Core/Threading/WorkerThread.cs.meta | 18 + Assets/Mirror/Core/Tools.meta | 3 + Assets/Mirror/Core/Tools/AccurateInterval.cs | 86 + .../Core/Tools/AccurateInterval.cs.meta | 18 + Assets/Mirror/Core/Tools/Compression.cs | 596 + Assets/Mirror/Core/Tools/Compression.cs.meta | 18 + Assets/Mirror/Core/Tools/DeltaCompression.cs | 58 + .../Core/Tools/DeltaCompression.cs.meta | 18 + .../Core/Tools/ExponentialMovingAverage.cs | 53 + .../Tools/ExponentialMovingAverage.cs.meta | 18 + Assets/Mirror/Core/Tools/Extensions.cs | 145 + Assets/Mirror/Core/Tools/Extensions.cs.meta | 18 + Assets/Mirror/Core/Tools/Half.cs | 773 + Assets/Mirror/Core/Tools/Half.cs.meta | 10 + Assets/Mirror/Core/Tools/Mathd.cs | 32 + Assets/Mirror/Core/Tools/Mathd.cs.meta | 18 + Assets/Mirror/Core/Tools/Pool.cs | 48 + Assets/Mirror/Core/Tools/Pool.cs.meta | 18 + Assets/Mirror/Core/Tools/Readme.txt | 1 + Assets/Mirror/Core/Tools/Readme.txt.meta | 10 + Assets/Mirror/Core/Tools/TimeSample.cs | 61 + Assets/Mirror/Core/Tools/TimeSample.cs.meta | 18 + Assets/Mirror/Core/Tools/Utils.cs | 222 + Assets/Mirror/Core/Tools/Utils.cs.meta | 18 + Assets/Mirror/Core/Tools/Vector3Long.cs | 125 + Assets/Mirror/Core/Tools/Vector3Long.cs.meta | 18 + Assets/Mirror/Core/Tools/Vector4Long.cs | 126 + Assets/Mirror/Core/Tools/Vector4Long.cs.meta | 10 + Assets/Mirror/Core/Transport.cs | 210 + Assets/Mirror/Core/Transport.cs.meta | 18 + Assets/Mirror/Core/TransportError.cs | 17 + Assets/Mirror/Core/TransportError.cs.meta | 18 + Assets/Mirror/Core/WeaverFuse.cs | 22 + Assets/Mirror/Core/WeaverFuse.cs.meta | 18 + Assets/Mirror/Editor.meta | 8 + Assets/Mirror/Editor/AndroidManifestHelper.cs | 116 + .../Editor/AndroidManifestHelper.cs.meta | 18 + Assets/Mirror/Editor/EditorHelper.cs | 41 + Assets/Mirror/Editor/EditorHelper.cs.meta | 18 + Assets/Mirror/Editor/Icon.meta | 8 + Assets/Mirror/Editor/Icon/MirrorIcon.png | Bin 0 -> 138247 bytes Assets/Mirror/Editor/Icon/MirrorIcon.png.meta | 117 + Assets/Mirror/Editor/InspectorHelper.cs | 77 + Assets/Mirror/Editor/InspectorHelper.cs.meta | 18 + .../Mirror/Editor/LagCompensatorInspector.cs | 14 + .../Editor/LagCompensatorInspector.cs.meta | 18 + Assets/Mirror/Editor/Mirror.Editor.asmdef | 20 + .../Mirror/Editor/Mirror.Editor.asmdef.meta | 14 + .../Editor/NetworkBehaviourInspector.cs | 104 + .../Editor/NetworkBehaviourInspector.cs.meta | 18 + .../Editor/NetworkInformationPreview.cs | 307 + .../Editor/NetworkInformationPreview.cs.meta | 18 + Assets/Mirror/Editor/NetworkManagerEditor.cs | 203 + .../Editor/NetworkManagerEditor.cs.meta | 18 + .../Mirror/Editor/NetworkScenePostProcess.cs | 107 + .../Editor/NetworkScenePostProcess.cs.meta | 18 + Assets/Mirror/Editor/ReadOnlyDrawer.cs | 19 + Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta | 18 + Assets/Mirror/Editor/SceneDrawer.cs | 47 + Assets/Mirror/Editor/SceneDrawer.cs.meta | 18 + .../Editor/SyncObjectCollectionsDrawer.cs | 89 + .../SyncObjectCollectionsDrawer.cs.meta | 10 + .../Mirror/Editor/SyncVarAttributeDrawer.cs | 28 + .../Editor/SyncVarAttributeDrawer.cs.meta | 18 + Assets/Mirror/Editor/Weaver.meta | 8 + Assets/Mirror/Editor/Weaver/AssemblyInfo.cs | 3 + .../Mirror/Editor/Weaver/AssemblyInfo.cs.meta | 18 + Assets/Mirror/Editor/Weaver/EntryPoint.meta | 3 + .../EntryPoint/CompilationFinishedHook.cs | 188 + .../CompilationFinishedHook.cs.meta | 18 + .../EntryPoint/CompilationFinishedLogger.cs | 31 + .../CompilationFinishedLogger.cs.meta | 10 + .../Weaver/EntryPoint/EnterPlayModeHook.cs | 44 + .../EntryPoint/EnterPlayModeHook.cs.meta | 10 + .../Weaver/EntryPointILPostProcessor.meta | 3 + .../CompiledAssemblyFromFile.cs | 31 + .../CompiledAssemblyFromFile.cs.meta | 10 + .../ILPostProcessorAssemblyResolver.cs | 205 + .../ILPostProcessorAssemblyResolver.cs.meta | 10 + .../ILPostProcessorFromFile.cs | 53 + .../ILPostProcessorFromFile.cs.meta | 10 + .../ILPostProcessorHook.cs | 143 + .../ILPostProcessorHook.cs.meta | 10 + .../ILPostProcessorLogger.cs | 68 + .../ILPostProcessorLogger.cs.meta | 10 + .../ILPostProcessorReflectionImporter.cs | 36 + .../ILPostProcessorReflectionImporter.cs.meta | 10 + ...PostProcessorReflectionImporterProvider.cs | 16 + ...rocessorReflectionImporterProvider.cs.meta | 10 + Assets/Mirror/Editor/Weaver/Extensions.cs | 359 + .../Mirror/Editor/Weaver/Extensions.cs.meta | 18 + Assets/Mirror/Editor/Weaver/Helpers.cs | 26 + Assets/Mirror/Editor/Weaver/Helpers.cs.meta | 18 + Assets/Mirror/Editor/Weaver/Logger.cs | 13 + Assets/Mirror/Editor/Weaver/Logger.cs.meta | 18 + Assets/Mirror/Editor/Weaver/Processors.meta | 8 + .../Weaver/Processors/CommandProcessor.cs | 130 + .../Processors/CommandProcessor.cs.meta | 18 + .../Weaver/Processors/MethodProcessor.cs | 139 + .../Weaver/Processors/MethodProcessor.cs.meta | 18 + .../Processors/MonoBehaviourProcessor.cs | 56 + .../Processors/MonoBehaviourProcessor.cs.meta | 18 + .../Processors/NetworkBehaviourProcessor.cs | 1055 ++ .../NetworkBehaviourProcessor.cs.meta | 18 + .../Processors/ReaderWriterProcessor.cs | 260 + .../Processors/ReaderWriterProcessor.cs.meta | 18 + .../Editor/Weaver/Processors/RpcProcessor.cs | 104 + .../Weaver/Processors/RpcProcessor.cs.meta | 18 + .../ServerClientAttributeProcessor.cs | 163 + .../ServerClientAttributeProcessor.cs.meta | 18 + .../Processors/SyncObjectInitializer.cs | 39 + .../Processors/SyncObjectInitializer.cs.meta | 18 + .../Weaver/Processors/SyncObjectProcessor.cs | 90 + .../Processors/SyncObjectProcessor.cs.meta | 18 + .../SyncVarAttributeAccessReplacer.cs | 206 + .../SyncVarAttributeAccessReplacer.cs.meta | 18 + .../Processors/SyncVarAttributeProcessor.cs | 515 + .../SyncVarAttributeProcessor.cs.meta | 18 + .../Weaver/Processors/TargetRpcProcessor.cs | 159 + .../Processors/TargetRpcProcessor.cs.meta | 18 + Assets/Mirror/Editor/Weaver/Readers.cs | 404 + Assets/Mirror/Editor/Weaver/Readers.cs.meta | 18 + Assets/Mirror/Editor/Weaver/Resolvers.cs | 126 + Assets/Mirror/Editor/Weaver/Resolvers.cs.meta | 18 + .../Editor/Weaver/SyncVarAccessLists.cs | 32 + .../Editor/Weaver/SyncVarAccessLists.cs.meta | 10 + .../Editor/Weaver/TypeReferenceComparer.cs | 15 + .../Weaver/TypeReferenceComparer.cs.meta | 18 + .../Editor/Weaver/Unity.Mirror.CodeGen.asmdef | 21 + .../Weaver/Unity.Mirror.CodeGen.asmdef.meta | 14 + Assets/Mirror/Editor/Weaver/Weaver.cs | 267 + Assets/Mirror/Editor/Weaver/Weaver.cs.meta | 18 + .../Mirror/Editor/Weaver/WeaverExceptions.cs | 26 + .../Editor/Weaver/WeaverExceptions.cs.meta | 18 + Assets/Mirror/Editor/Weaver/WeaverTypes.cs | 171 + .../Mirror/Editor/Weaver/WeaverTypes.cs.meta | 10 + Assets/Mirror/Editor/Weaver/Writers.cs | 360 + Assets/Mirror/Editor/Weaver/Writers.cs.meta | 18 + Assets/Mirror/Editor/Welcome.cs | 23 + Assets/Mirror/Editor/Welcome.cs.meta | 18 + Assets/Mirror/Examples.meta | 8 + Assets/Mirror/Examples/AdditiveLevels.meta | 8 + .../Examples/AdditiveLevels/Materials.meta | 8 + .../AdditiveLevels/Materials/CubeSphere.mat | 77 + .../Materials/CubeSphere.mat.meta | 15 + .../AdditiveLevels/Materials/Ground.mat | 77 + .../AdditiveLevels/Materials/Ground.mat.meta | 15 + .../AdditiveLevels/Materials/Player.mat | 77 + .../AdditiveLevels/Materials/Player.mat.meta | 15 + .../AdditiveLevels/Materials/Portal.mat | 78 + .../AdditiveLevels/Materials/Portal.mat.meta | 15 + .../AdditiveLevels/Materials/Skybox.mat | 104 + .../AdditiveLevels/Materials/Skybox.mat.meta | 16 + .../AdditiveLevels/Materials/StartPoint.mat | 78 + .../Materials/StartPoint.mat.meta | 15 + .../Examples/AdditiveLevels/Prefabs.meta | 8 + .../AdditiveLevels/Prefabs/Cube.prefab | 132 + .../AdditiveLevels/Prefabs/Cube.prefab.meta | 14 + .../AdditiveLevels/Prefabs/Plane.prefab | 152 + .../AdditiveLevels/Prefabs/Plane.prefab.meta | 14 + .../Prefabs/PlayerReliable.prefab | 385 + .../Prefabs/PlayerReliable.prefab.meta | 14 + .../Prefabs/PlayerUnreliable.prefab | 385 + .../Prefabs/PlayerUnreliable.prefab.meta | 14 + .../AdditiveLevels/Prefabs/Portal.prefab | 246 + .../AdditiveLevels/Prefabs/Portal.prefab.meta | 14 + .../AdditiveLevels/Prefabs/Sphere.prefab | 132 + .../AdditiveLevels/Prefabs/Sphere.prefab.meta | 14 + .../AdditiveLevels/Prefabs/StartPoint.prefab | 85 + .../Prefabs/StartPoint.prefab.meta | 14 + .../Mirror/Examples/AdditiveLevels/ReadMe.txt | 1 + .../Examples/AdditiveLevels/ReadMe.txt.meta | 14 + .../Examples/AdditiveLevels/Scenes.meta | 8 + .../Scenes/MirrorAdditiveLevelsOffline.unity | 510 + .../MirrorAdditiveLevelsOffline.unity.meta | 14 + .../Scenes/MirrorAdditiveLevelsOnline.meta | 8 + .../Scenes/MirrorAdditiveLevelsOnline.unity | 816 ++ .../MirrorAdditiveLevelsOnline.unity.meta | 14 + .../LightingData.asset | Bin 0 -> 19648 bytes .../LightingData.asset.meta | 15 + .../ReflectionProbe-0.exr | Bin 0 -> 140188 bytes .../ReflectionProbe-0.exr.meta | 99 + .../MirrorAdditiveLevelsSubLevel1.unity | 1042 ++ .../MirrorAdditiveLevelsSubLevel1.unity.meta | 14 + .../MirrorAdditiveLevelsSubLevel2.unity | 841 ++ .../MirrorAdditiveLevelsSubLevel2.unity.meta | 14 + .../Examples/AdditiveLevels/Scripts.meta | 8 + .../Scripts/AdditiveLevelsNetworkManager.cs | 187 + .../AdditiveLevelsNetworkManager.cs.meta | 18 + .../AdditiveLevels/Scripts/FadeInOut.cs | 77 + .../AdditiveLevels/Scripts/FadeInOut.cs.meta | 18 + .../Scripts/LookAtMainCamera.cs | 21 + .../Scripts/LookAtMainCamera.cs.meta | 18 + .../Examples/AdditiveLevels/Scripts/Portal.cs | 104 + .../AdditiveLevels/Scripts/Portal.cs.meta | 18 + .../Examples/AdditiveLevels/Textures.meta | 9 + .../AdditiveLevels/Textures/Back_Tex.jpeg | Bin 0 -> 68766 bytes .../Textures/Back_Tex.jpeg.meta | 99 + .../AdditiveLevels/Textures/Down_Tex.jpeg | Bin 0 -> 75605 bytes .../Textures/Down_Tex.jpeg.meta | 99 + .../AdditiveLevels/Textures/Front_Tex.jpeg | Bin 0 -> 72964 bytes .../Textures/Front_Tex.jpeg.meta | 99 + .../AdditiveLevels/Textures/Left_Tex.jpeg | Bin 0 -> 68026 bytes .../Textures/Left_Tex.jpeg.meta | 99 + .../AdditiveLevels/Textures/Right_Tex.jpeg | Bin 0 -> 70199 bytes .../Textures/Right_Tex.jpeg.meta | 99 + .../AdditiveLevels/Textures/Up_Tex.jpeg | Bin 0 -> 69705 bytes .../AdditiveLevels/Textures/Up_Tex.jpeg.meta | 99 + Assets/Mirror/Examples/AdditiveScenes.meta | 8 + .../Examples/AdditiveScenes/Materials.meta | 8 + .../AdditiveScenes/Materials/Capsule.mat | 77 + .../AdditiveScenes/Materials/Capsule.mat.meta | 15 + .../AdditiveScenes/Materials/Cube.mat | 77 + .../AdditiveScenes/Materials/Cube.mat.meta | 15 + .../AdditiveScenes/Materials/Cylinder.mat | 77 + .../Materials/Cylinder.mat.meta | 15 + .../AdditiveScenes/Materials/Player.mat | 77 + .../AdditiveScenes/Materials/Player.mat.meta | 15 + .../AdditiveScenes/Materials/Quad.mat | 77 + .../AdditiveScenes/Materials/Quad.mat.meta | 15 + .../AdditiveScenes/Materials/Shelter.mat | 77 + .../AdditiveScenes/Materials/Shelter.mat.meta | 15 + .../AdditiveScenes/Materials/Sphere.mat | 77 + .../AdditiveScenes/Materials/Sphere.mat.meta | 15 + .../AdditiveScenes/Materials/Zone.mat | 78 + .../AdditiveScenes/Materials/Zone.mat.meta | 15 + .../Examples/AdditiveScenes/Prefabs.meta | 8 + .../AdditiveScenes/Prefabs/Capsule.prefab | 145 + .../Prefabs/Capsule.prefab.meta | 14 + .../AdditiveScenes/Prefabs/Cube.prefab | 144 + .../AdditiveScenes/Prefabs/Cube.prefab.meta | 14 + .../AdditiveScenes/Prefabs/Cylinder.prefab | 145 + .../Prefabs/Cylinder.prefab.meta | 14 + .../Prefabs/PlayerReliable.prefab | 402 + .../Prefabs/PlayerReliable.prefab.meta | 14 + .../Prefabs/PlayerUnreliable.prefab | 402 + .../Prefabs/PlayerUnreliable.prefab.meta | 14 + .../AdditiveScenes/Prefabs/Sphere.prefab | 144 + .../AdditiveScenes/Prefabs/Sphere.prefab.meta | 14 + .../AdditiveScenes/Prefabs/Tank.prefab | 180 + .../AdditiveScenes/Prefabs/Tank.prefab.meta | 14 + .../AdditiveScenes/Prefabs/Zone.prefab | 60 + .../AdditiveScenes/Prefabs/Zone.prefab.meta | 14 + .../Mirror/Examples/AdditiveScenes/README.md | 24 + .../Examples/AdditiveScenes/README.md.meta | 14 + .../Examples/AdditiveScenes/Scenes.meta | 8 + .../Scenes/MirrorAdditiveScenesMain.meta | 8 + .../Scenes/MirrorAdditiveScenesMain.unity | 2167 +++ .../MirrorAdditiveScenesMain.unity.meta | 14 + .../LightingData.asset | Bin 0 -> 19240 bytes .../LightingData.asset.meta | 15 + .../ReflectionProbe-0.exr | Bin 0 -> 110488 bytes .../ReflectionProbe-0.exr.meta | 99 + .../Scenes/MirrorAdditiveScenesSubScene.unity | 840 ++ .../MirrorAdditiveScenesSubScene.unity.meta | 14 + .../Examples/AdditiveScenes/Scripts.meta | 8 + .../Scripts/AdditiveNetworkManager.cs | 58 + .../Scripts/AdditiveNetworkManager.cs.meta | 18 + .../Scripts/ShootingTankBehaviour.cs | 59 + .../Scripts/ShootingTankBehaviour.cs.meta | 18 + .../AdditiveScenes/Scripts/ZoneHandler.cs | 42 + .../Scripts/ZoneHandler.cs.meta | 18 + .../Examples/AutoLANClientController.meta | 8 + .../MirrorAutoLANClientController.unity | 3214 ++++ .../MirrorAutoLANClientController.unity.meta | 14 + .../AutoLANClientController/Prefabs.meta | 8 + .../Prefabs/PlayerController.prefab | 50 + .../Prefabs/PlayerController.prefab.meta | 14 + .../AutoLANClientController/Scripts.meta | 8 + .../Scripts/AutoLANNetworkDiscovery.cs | 105 + .../Scripts/AutoLANNetworkDiscovery.cs.meta | 18 + .../Scripts/AutoLANNetworkManager.cs | 336 + .../Scripts/AutoLANNetworkManager.cs.meta | 18 + .../Scripts/CanvasHUD.cs | 204 + .../Scripts/CanvasHUD.cs.meta | 18 + .../Scripts/NetworkSceneScript.cs | 48 + .../Scripts/NetworkSceneScript.cs.meta | 18 + Assets/Mirror/Examples/Basic.meta | 8 + Assets/Mirror/Examples/Basic/Prefabs.meta | 8 + .../Examples/Basic/Prefabs/Player.prefab | 73 + .../Examples/Basic/Prefabs/Player.prefab.meta | 14 + .../Examples/Basic/Prefabs/PlayerUI.prefab | 250 + .../Basic/Prefabs/PlayerUI.prefab.meta | 14 + Assets/Mirror/Examples/Basic/README.md | 16 + Assets/Mirror/Examples/Basic/README.md.meta | 14 + Assets/Mirror/Examples/Basic/Scenes.meta | 8 + .../Examples/Basic/Scenes/MirrorBasic.unity | 746 + .../Basic/Scenes/MirrorBasic.unity.meta | 14 + Assets/Mirror/Examples/Basic/Scripts.meta | 8 + .../Examples/Basic/Scripts/BasicNetManager.cs | 30 + .../Basic/Scripts/BasicNetManager.cs.meta | 18 + .../Mirror/Examples/Basic/Scripts/CanvasUI.cs | 28 + .../Examples/Basic/Scripts/CanvasUI.cs.meta | 18 + .../Mirror/Examples/Basic/Scripts/Player.cs | 181 + .../Examples/Basic/Scripts/Player.cs.meta | 18 + .../Mirror/Examples/Basic/Scripts/PlayerUI.cs | 41 + .../Examples/Basic/Scripts/PlayerUI.cs.meta | 18 + Assets/Mirror/Examples/Benchmark.meta | 8 + .../Mirror/Examples/Benchmark/Materials.meta | 8 + .../Examples/Benchmark/Materials/Red.mat | 77 + .../Examples/Benchmark/Materials/Red.mat.meta | 15 + .../Examples/Benchmark/Materials/White.mat | 77 + .../Benchmark/Materials/White.mat.meta | 15 + Assets/Mirror/Examples/Benchmark/Prefabs.meta | 8 + .../Examples/Benchmark/Prefabs/Monster.prefab | 152 + .../Benchmark/Prefabs/Monster.prefab.meta | 14 + .../Examples/Benchmark/Prefabs/Player.prefab | 150 + .../Benchmark/Prefabs/Player.prefab.meta | 14 + Assets/Mirror/Examples/Benchmark/Scenes.meta | 8 + .../Benchmark/Scenes/MirrorBenchmark.unity | 538 + .../Scenes/MirrorBenchmark.unity.meta | 14 + Assets/Mirror/Examples/Benchmark/Scripts.meta | 8 + .../Scripts/BenchmarkNetworkManager.cs | 52 + .../Scripts/BenchmarkNetworkManager.cs.meta | 18 + .../Benchmark/Scripts/MonsterMovement.cs | 57 + .../Benchmark/Scripts/MonsterMovement.cs.meta | 18 + .../Benchmark/Scripts/PlayerMovement.cs | 31 + .../Benchmark/Scripts/PlayerMovement.cs.meta | 18 + Assets/Mirror/Examples/BenchmarkIdle.meta | 8 + .../BenchmarkIdleNetworkManager.cs | 98 + .../BenchmarkIdleNetworkManager.cs.meta | 18 + .../BenchmarkIdle/MirrorBenchmarkIdle.unity | 519 + .../MirrorBenchmarkIdle.unity.meta | 14 + Assets/Mirror/Examples/BenchmarkIdle/Npc.cs | 39 + .../Mirror/Examples/BenchmarkIdle/Npc.cs.meta | 18 + Assets/Mirror/Examples/BenchmarkIdle/Npc.mat | 77 + .../Examples/BenchmarkIdle/Npc.mat.meta | 15 + .../Mirror/Examples/BenchmarkIdle/Npc.prefab | 119 + .../Examples/BenchmarkIdle/Npc.prefab.meta | 14 + .../Mirror/Examples/BenchmarkIdle/Player.cs | 87 + .../Examples/BenchmarkIdle/Player.cs.meta | 18 + .../Mirror/Examples/BenchmarkIdle/Player.mat | 77 + .../Examples/BenchmarkIdle/Player.mat.meta | 15 + .../Examples/BenchmarkIdle/Player.prefab | 154 + .../Examples/BenchmarkIdle/Player.prefab.meta | 14 + .../Mirror/Examples/BenchmarkIdle/Readme.txt | 9 + .../Examples/BenchmarkIdle/Readme.txt.meta | 10 + .../Mirror/Examples/BenchmarkIdle/_Readme.txt | 4 + .../Examples/BenchmarkIdle/_Readme.txt.meta | 10 + .../Mirror/Examples/BenchmarkPrediction.meta | 8 + .../BenchmarkPrediction/BallMaterial.mat | 80 + .../BenchmarkPrediction/BallMaterial.mat.meta | 15 + .../MirrorPredictionBenchmark.unity | 1002 ++ .../MirrorPredictionBenchmark.unity.meta | 14 + .../NetworkManagerPredictionBenchmark.cs | 50 + .../NetworkManagerPredictionBenchmark.cs.meta | 18 + .../PlayerSpectator.prefab | 50 + .../PlayerSpectator.prefab.meta | 14 + .../BenchmarkPrediction/PredictedBall.prefab | 186 + .../PredictedBall.prefab.meta | 14 + .../BenchmarkPrediction/RandomForce.cs | 52 + .../BenchmarkPrediction/RandomForce.cs.meta | 18 + .../Examples/BenchmarkPrediction/Readme.md | 24 + .../BenchmarkPrediction/Readme.md.meta | 10 + .../BenchmarkPrediction/WallMaterial.mat | 78 + .../BenchmarkPrediction/WallMaterial.mat.meta | 15 + .../Mirror/Examples/BenchmarkStinkySteak.meta | 8 + .../BehaviourConfig.asset | 33 + .../BehaviourConfig.asset.meta | 15 + .../BenchmarkStinkySteak/Dependencies.meta | 8 + .../Dependencies/Unity-Simulation-Timer.meta | 8 + .../Unity-Simulation-Timer/LICENSE.md | 21 + .../Unity-Simulation-Timer/LICENSE.md.meta | 14 + .../Unity-Simulation-Timer/README.md | 63 + .../Unity-Simulation-Timer/README.md.meta | 14 + .../Unity-Simulation-Timer/Runtime.meta | 8 + .../Runtime/PauseableSimulationTimer.cs | 63 + .../Runtime/PauseableSimulationTimer.cs.meta | 18 + .../Runtime/SimulationTimer.cs | 32 + .../Runtime/SimulationTimer.cs.meta | 18 + .../Unity-Simulation-Timer/package.json | 15 + .../Unity-Simulation-Timer/package.json.meta | 14 + .../netcode-benchmarker-util.meta | 8 + .../netcode-benchmarker-util/LICENSE.md | 21 + .../netcode-benchmarker-util/LICENSE.md.meta | 14 + .../netcode-benchmarker-util/Runtime.meta | 8 + .../Runtime/Config.meta | 8 + .../Config/DefaultBehaviourConfig.asset | 33 + .../Config/DefaultBehaviourConfig.asset.meta | 15 + .../Runtime/Prefabs.meta | 8 + .../Runtime/Prefabs/BaseGUIGame.prefab | 1499 ++ .../Runtime/Prefabs/BaseGUIGame.prefab.meta | 14 + .../Runtime/Scripts.meta | 8 + .../Runtime/Scripts/BehaviourConfig.cs | 45 + .../Runtime/Scripts/BehaviourConfig.cs.meta | 18 + .../Runtime/Scripts/BehaviourWrapper.meta | 8 + .../Scripts/BehaviourWrapper/IMoveWrapper.cs | 10 + .../BehaviourWrapper/IMoveWrapper.cs.meta | 18 + .../BehaviourWrapper/SinMoveYWrapper.cs | 45 + .../BehaviourWrapper/SinMoveYWrapper.cs.meta | 18 + .../BehaviourWrapper/SinRandomMoveWrapper.cs | 40 + .../SinRandomMoveWrapper.cs.meta | 18 + .../BehaviourWrapper/WanderMoveWrapper.cs | 86 + .../WanderMoveWrapper.cs.meta | 18 + .../Runtime/Scripts/RandomVector3.cs | 16 + .../Runtime/Scripts/RandomVector3.cs.meta | 18 + .../Runtime/Scripts/UI.meta | 8 + .../Runtime/Scripts/UI/BaseGUIGame.cs | 94 + .../Runtime/Scripts/UI/BaseGUIGame.cs.meta | 18 + .../Runtime/Shaders.meta | 8 + .../Runtime/Shaders/Unlit.mat | 28 + .../Runtime/Shaders/Unlit.mat.meta | 15 + .../Runtime/Shaders/Unlit.shader | 37 + .../Runtime/Shaders/Unlit.shader.meta | 17 + .../Examples/BenchmarkStinkySteak/LICENSE.md | 21 + .../BenchmarkStinkySteak/LICENSE.md.meta | 14 + .../Examples/BenchmarkStinkySteak/Main.unity | 337 + .../BenchmarkStinkySteak/Main.unity.meta | 14 + .../BenchmarkStinkySteak/Prefabs.meta | 8 + .../Prefabs/GUIGame.prefab | 1371 ++ .../Prefabs/GUIGame.prefab.meta | 14 + .../Prefabs/NetworkManager.prefab | 111 + .../Prefabs/NetworkManager.prefab.meta | 14 + .../Prefabs/PlayerDummy.prefab | 50 + .../Prefabs/PlayerDummy.prefab.meta | 14 + .../Prefabs/SphereMoveAllAxis.prefab | 181 + .../Prefabs/SphereMoveAllAxis.prefab.meta | 14 + .../Prefabs/SphereMoveWander.prefab | 181 + .../Prefabs/SphereMoveWander.prefab.meta | 14 + .../Prefabs/SphereMoveY.prefab | 181 + .../Prefabs/SphereMoveY.prefab.meta | 14 + .../BenchmarkStinkySteak/Scripts.meta | 8 + .../BenchmarkStinkySteak/Scripts/GUIGame.cs | 65 + .../Scripts/GUIGame.cs.meta | 18 + .../Scripts/SineMoveRandomBehaviour.cs | 27 + .../Scripts/SineMoveRandomBehaviour.cs.meta | 18 + .../Scripts/SineMoveYBehaviour.cs | 27 + .../Scripts/SineMoveYBehaviour.cs.meta | 18 + .../Scripts/WanderMoveBehaviour.cs | 27 + .../Scripts/WanderMoveBehaviour.cs.meta | 18 + .../BenchmarkStinkySteak/Shaders.meta | 8 + .../BenchmarkStinkySteak/Shaders/Unlit.mat | 28 + .../Shaders/Unlit.mat.meta | 15 + .../BenchmarkStinkySteak/Shaders/Unlit.shader | 37 + .../Shaders/Unlit.shader.meta | 17 + .../Examples/BenchmarkStinkySteak/_Readme.txt | 10 + .../BenchmarkStinkySteak/_Readme.txt.meta | 14 + Assets/Mirror/Examples/Billiards.meta | 8 + Assets/Mirror/Examples/Billiards/Ball.meta | 8 + .../Billiards/Ball/Ball.physicMaterial | 14 + .../Billiards/Ball/Ball.physicMaterial.meta | 15 + Assets/Mirror/Examples/Billiards/Ball/Red.mat | 80 + .../Examples/Billiards/Ball/Red.mat.meta | 15 + .../Mirror/Examples/Billiards/Ball/Red.prefab | 181 + .../Examples/Billiards/Ball/Red.prefab.meta | 14 + .../Mirror/Examples/Billiards/Ball/RedBall.cs | 15 + .../Examples/Billiards/Ball/RedBall.cs.meta | 18 + .../Mirror/Examples/Billiards/Ball/White.mat | 80 + .../Examples/Billiards/Ball/White.mat.meta | 15 + .../Examples/Billiards/Ball/White.prefab | 314 + .../Examples/Billiards/Ball/White.prefab.meta | 14 + .../Examples/Billiards/Ball/WhiteBall.cs | 107 + .../Examples/Billiards/Ball/WhiteBall.cs.meta | 18 + .../Examples/Billiards/MirrorBilliards.unity | 1445 ++ .../Billiards/MirrorBilliards.unity.meta | 14 + .../Mirror/Examples/Billiards/Player.prefab | 50 + .../Examples/Billiards/Player.prefab.meta | 14 + Assets/Mirror/Examples/Billiards/Table.meta | 8 + .../Billiards/Table/Billiard Table.prefab | 468 + .../Table/Billiard Table.prefab.meta | 14 + .../Billiards/Table/BilliardTable Model.obj | 4468 ++++++ .../Table/BilliardTable Model.obj.meta | 113 + .../Billiards/Table/BilliardTable.mtl | 52 + .../Billiards/Table/BilliardTable.mtl.meta | 14 + .../Mirror/Examples/Billiards/Table/Body.mat | 81 + .../Examples/Billiards/Table/Body.mat.meta | 15 + .../Mirror/Examples/Billiards/Table/Edge.mat | 80 + .../Examples/Billiards/Table/Edge.mat.meta | 15 + .../Mirror/Examples/Billiards/Table/Felt.mat | 80 + .../Examples/Billiards/Table/Felt.mat.meta | 15 + .../Mirror/Examples/Billiards/Table/Holes.mat | 80 + .../Examples/Billiards/Table/Holes.mat.meta | 15 + .../Mirror/Examples/Billiards/Table/Lamp.mat | 80 + .../Examples/Billiards/Table/Lamp.mat.meta | 15 + .../Examples/Billiards/Table/License.txt | 3 + .../Examples/Billiards/Table/License.txt.meta | 10 + .../Examples/Billiards/Table/Pockets.mat | 82 + .../Examples/Billiards/Table/Pockets.mat.meta | 15 + Assets/Mirror/Examples/Billiards/_Readme.txt | 18 + .../Examples/Billiards/_Readme.txt.meta | 10 + .../Mirror/Examples/BilliardsPredicted.meta | 8 + .../Examples/BilliardsPredicted/Ball.meta | 8 + .../BilliardsPredicted/Ball/Pockets.cs | 42 + .../BilliardsPredicted/Ball/Pockets.cs.meta | 18 + .../Examples/BilliardsPredicted/Ball/Red.mat | 80 + .../BilliardsPredicted/Ball/Red.mat.meta | 15 + .../Ball/RedBallPredicted.cs | 22 + .../Ball/RedBallPredicted.cs.meta | 18 + .../Ball/RedPredicted.prefab | 184 + .../Ball/RedPredicted.prefab.meta | 14 + .../BilliardsPredicted/Ball/White.mat | 80 + .../BilliardsPredicted/Ball/White.mat.meta | 15 + .../Ball/WhiteBallPredicted.cs | 186 + .../Ball/WhiteBallPredicted.cs.meta | 18 + .../Ball/WhitePredicted.prefab | 318 + .../Ball/WhitePredicted.prefab.meta | 14 + .../MirrorBilliardsPredicted.unity | 1410 ++ .../MirrorBilliardsPredicted.unity.meta | 14 + .../Examples/BilliardsPredicted/Player.meta | 8 + .../Player/PlayerPredicted.cs | 91 + .../Player/PlayerPredicted.cs.meta | 18 + .../Player/PlayerPredicted.prefab | 66 + .../Player/PlayerPredicted.prefab.meta | 14 + .../Examples/BilliardsPredicted/_Readme.txt | 19 + .../BilliardsPredicted/_Readme.txt.meta | 10 + Assets/Mirror/Examples/CCU.meta | 8 + .../Mirror/Examples/CCU/CCUNetworkManager.cs | 93 + .../Examples/CCU/CCUNetworkManager.cs.meta | 18 + Assets/Mirror/Examples/CCU/MirrorCCU.unity | 541 + .../Mirror/Examples/CCU/MirrorCCU.unity.meta | 14 + Assets/Mirror/Examples/CCU/Monster.cs | 55 + Assets/Mirror/Examples/CCU/Monster.cs.meta | 18 + Assets/Mirror/Examples/CCU/Monster.prefab | 152 + .../Mirror/Examples/CCU/Monster.prefab.meta | 14 + Assets/Mirror/Examples/CCU/Player.cs | 99 + Assets/Mirror/Examples/CCU/Player.cs.meta | 18 + Assets/Mirror/Examples/CCU/Player.prefab | 175 + Assets/Mirror/Examples/CCU/Player.prefab.meta | 14 + Assets/Mirror/Examples/CCU/Readme.txt | 9 + Assets/Mirror/Examples/CCU/Readme.txt.meta | 10 + Assets/Mirror/Examples/CCU/Red.mat | 77 + Assets/Mirror/Examples/CCU/Red.mat.meta | 15 + Assets/Mirror/Examples/CCU/White.mat | 77 + Assets/Mirror/Examples/CCU/White.mat.meta | 15 + .../Mirror/Examples/CharacterSelection.meta | 8 + .../CharacterSelection/Materials.meta | 8 + .../Materials/MaterialBlack.mat | 80 + .../Materials/MaterialBlack.mat.meta | 15 + .../Materials/MaterialBrown.mat | 80 + .../Materials/MaterialBrown.mat.meta | 15 + .../Materials/MaterialDesert.mat | 80 + .../Materials/MaterialDesert.mat.meta | 15 + .../Materials/MaterialFloor.mat | 80 + .../Materials/MaterialFloor.mat.meta | 15 + .../Materials/MaterialGold.mat | 80 + .../Materials/MaterialGold.mat.meta | 15 + .../Materials/MaterialGreenDark.mat | 80 + .../Materials/MaterialGreenDark.mat.meta | 15 + .../Materials/MaterialIcon1.mat | 80 + .../Materials/MaterialIcon1.mat.meta | 15 + .../Materials/MaterialRed.mat | 80 + .../Materials/MaterialRed.mat.meta | 15 + .../Materials/MaterialSilver.mat | 80 + .../Materials/MaterialSilver.mat.meta | 15 + .../Materials/MaterialWhite.mat | 80 + .../Materials/MaterialWhite.mat.meta | 15 + .../MirrorCharacterSelection.unity | 3307 +++++ .../MirrorCharacterSelection.unity.meta | 14 + .../MirrorCharacterSelectionNoCharacter.unity | 3308 +++++ ...orCharacterSelectionNoCharacter.unity.meta | 14 + .../MirrorCharacterSelectionPreScene.unity | 332 + ...irrorCharacterSelectionPreScene.unity.meta | 14 + .../Examples/CharacterSelection/Prefabs.meta | 8 + .../Prefabs/CharacterData.prefab | 67 + .../Prefabs/CharacterData.prefab.meta | 14 + .../Prefabs/CharacterSelection.prefab | 2696 ++++ .../Prefabs/CharacterSelection.prefab.meta | 14 + .../Prefabs/Characters.meta | 8 + .../Characters/CharacterAssault.prefab | 1961 +++ .../Characters/CharacterAssault.prefab.meta | 14 + .../Prefabs/Characters/CharacterHeavy.prefab | 1478 ++ .../Characters/CharacterHeavy.prefab.meta | 14 + .../Prefabs/Characters/CharacterMedic.prefab | 1157 ++ .../Characters/CharacterMedic.prefab.meta | 14 + .../Prefabs/PlayerEmpty.prefab | 66 + .../Prefabs/PlayerEmpty.prefab.meta | 14 + .../Examples/CharacterSelection/Scripts.meta | 8 + .../Scripts/CanvasReferencer.cs | 194 + .../Scripts/CanvasReferencer.cs.meta | 18 + .../Scripts/CharacterData.cs | 25 + .../Scripts/CharacterData.cs.meta | 18 + .../Scripts/CharacterSelection.cs | 62 + .../Scripts/CharacterSelection.cs.meta | 18 + .../NetworkManagerCharacterSelection.cs | 135 + .../NetworkManagerCharacterSelection.cs.meta | 18 + .../CharacterSelection/Scripts/PlayerEmpty.cs | 22 + .../Scripts/PlayerEmpty.cs.meta | 18 + .../CharacterSelection/Scripts/SceneCamera.cs | 59 + .../Scripts/SceneCamera.cs.meta | 18 + .../Scripts/SceneReferencer.cs | 47 + .../Scripts/SceneReferencer.cs.meta | 18 + .../Scripts/ScriptAnimations.cs | 33 + .../Scripts/ScriptAnimations.cs.meta | 18 + .../Scripts/StaticVariables.cs | 13 + .../Scripts/StaticVariables.cs.meta | 18 + .../Examples/CharacterSelection/Textures.meta | 8 + .../Textures/IconRandomColour.png | Bin 0 -> 89302 bytes .../Textures/IconRandomColour.png.meta | 166 + .../Textures/IconResetColour.png | Bin 0 -> 18042 bytes .../Textures/IconResetColour.png.meta | 166 + .../Textures/IconStickPerson.png | Bin 0 -> 11503 bytes .../Textures/IconStickPerson.png.meta | 166 + .../CharacterSelection/Textures/dirtMoon.jpg | Bin 0 -> 20017 bytes .../Textures/dirtMoon.jpg.meta | 166 + .../Examples/CharacterSelection/_ReadMe.txt | 13 + .../CharacterSelection/_ReadMe.txt.meta | 14 + Assets/Mirror/Examples/Chat.meta | 8 + Assets/Mirror/Examples/Chat/Prefabs.meta | 8 + .../Examples/Chat/Prefabs/Player.prefab | 67 + .../Examples/Chat/Prefabs/Player.prefab.meta | 14 + Assets/Mirror/Examples/Chat/Scenes.meta | 8 + .../Examples/Chat/Scenes/MirrorChat.unity | 3706 +++++ .../Chat/Scenes/MirrorChat.unity.meta | 14 + Assets/Mirror/Examples/Chat/Scripts.meta | 8 + .../Chat/Scripts/ChatAuthenticator.cs | 213 + .../Chat/Scripts/ChatAuthenticator.cs.meta | 18 + .../Chat/Scripts/ChatNetworkManager.cs | 34 + .../Chat/Scripts/ChatNetworkManager.cs.meta | 18 + Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs | 100 + .../Examples/Chat/Scripts/ChatUI.cs.meta | 18 + .../Mirror/Examples/Chat/Scripts/LoginUI.cs | 52 + .../Examples/Chat/Scripts/LoginUI.cs.meta | 18 + Assets/Mirror/Examples/Chat/Scripts/Player.cs | 18 + .../Examples/Chat/Scripts/Player.cs.meta | 18 + Assets/Mirror/Examples/CouchCoop.meta | 8 + .../Mirror/Examples/CouchCoop/Materials.meta | 8 + .../CouchCoop/Materials/MaterialColliders.mat | 82 + .../Materials/MaterialColliders.mat.meta | 15 + .../CouchCoop/Materials/MaterialGround.mat | 80 + .../Materials/MaterialGround.mat.meta | 15 + .../CouchCoop/Materials/MaterialPlatform1.mat | 80 + .../Materials/MaterialPlatform1.mat.meta | 15 + .../CouchCoop/Materials/MaterialPlatform2.mat | 80 + .../Materials/MaterialPlatform2.mat.meta | 15 + .../CouchCoop/Materials/MaterialPlayer.mat | 82 + .../Materials/MaterialPlayer.mat.meta | 15 + .../Examples/CouchCoop/MirrorCouchCoop.unity | 3630 +++++ .../CouchCoop/MirrorCouchCoop.unity.meta | 14 + Assets/Mirror/Examples/CouchCoop/Prefabs.meta | 8 + .../CouchCoop/Prefabs/CouchPlayer.prefab | 526 + .../CouchCoop/Prefabs/CouchPlayer.prefab.meta | 14 + .../Prefabs/CouchPlayerManager.prefab | 73 + .../Prefabs/CouchPlayerManager.prefab.meta | 14 + Assets/Mirror/Examples/CouchCoop/Scripts.meta | 8 + .../CouchCoop/Scripts/CameraViewForAll.cs | 73 + .../Scripts/CameraViewForAll.cs.meta | 18 + .../CouchCoop/Scripts/CanvasScript.cs | 32 + .../CouchCoop/Scripts/CanvasScript.cs.meta | 18 + .../Examples/CouchCoop/Scripts/CouchPlayer.cs | 129 + .../CouchCoop/Scripts/CouchPlayer.cs.meta | 18 + .../CouchCoop/Scripts/CouchPlayerManager.cs | 69 + .../Scripts/CouchPlayerManager.cs.meta | 18 + .../CouchCoop/Scripts/MovingPlatform.cs | 79 + .../CouchCoop/Scripts/MovingPlatform.cs.meta | 18 + .../CouchCoop/Scripts/PlatformMovement.cs | 49 + .../Scripts/PlatformMovement.cs.meta | 18 + Assets/Mirror/Examples/CouchCoop/_ReadMe.txt | 16 + .../Examples/CouchCoop/_ReadMe.txt.meta | 14 + Assets/Mirror/Examples/Discovery.meta | 8 + Assets/Mirror/Examples/Discovery/Prefabs.meta | 8 + .../Examples/Discovery/Prefabs/Player.prefab | 114 + .../Discovery/Prefabs/Player.prefab.meta | 14 + Assets/Mirror/Examples/Discovery/Scenes.meta | 8 + .../Discovery/Scenes/MirrorDiscovery.unity | 790 + .../Scenes/MirrorDiscovery.unity.meta | 14 + Assets/Mirror/Examples/EdgegapLobby.meta | 8 + .../EdgegapLobby/EdgegapLobbyTanks.meta | 8 + .../EdgegapLobby/EdgegapLobbyTanks.unity | 1128 ++ .../EdgegapLobby/EdgegapLobbyTanks.unity.meta | 14 + .../EdgegapLobbyTanks/NavMesh.asset | Bin 0 -> 6564 bytes .../EdgegapLobbyTanks/NavMesh.asset.meta | 15 + .../Mirror/Examples/EdgegapLobby/Prefabs.meta | 8 + .../EdgegapLobby/Prefabs/LobbyUI.prefab | 4617 ++++++ .../EdgegapLobby/Prefabs/LobbyUI.prefab.meta | 14 + .../EdgegapLobby/Prefabs/LobbyUIEntry.prefab | 294 + .../Prefabs/LobbyUIEntry.prefab.meta | 14 + .../Mirror/Examples/EdgegapLobby/Scripts.meta | 8 + .../EdgegapLobby/Scripts/UILobbyCreate.cs | 54 + .../Scripts/UILobbyCreate.cs.meta | 10 + .../EdgegapLobby/Scripts/UILobbyEntry.cs | 37 + .../EdgegapLobby/Scripts/UILobbyEntry.cs.meta | 18 + .../EdgegapLobby/Scripts/UILobbyList.cs | 91 + .../EdgegapLobby/Scripts/UILobbyList.cs.meta | 10 + .../EdgegapLobby/Scripts/UILobbyStatus.cs | 121 + .../Scripts/UILobbyStatus.cs.meta | 10 + .../Mirror/Examples/EdgegapLobby/_ReadMe.txt | 11 + .../Examples/EdgegapLobby/_ReadMe.txt.meta | 14 + Assets/Mirror/Examples/HexSpatialHash.meta | 8 + .../HexSpatialHash/Hex2DSpatialHash.unity | 510 + .../Hex2DSpatialHash.unity.meta | 14 + .../HexSpatialHash/Hex3DSpatialHash.unity | 509 + .../Hex3DSpatialHash.unity.meta | 14 + .../Examples/HexSpatialHash/Mateirals.meta | 8 + .../HexSpatialHash/Mateirals/RandomColor.mat | 77 + .../Mateirals/RandomColor.mat.meta | 15 + .../Examples/HexSpatialHash/Prefabs.meta | 8 + .../HexSpatialHash/Prefabs/Hex2DPlayer.prefab | 170 + .../Prefabs/Hex2DPlayer.prefab.meta | 14 + .../HexSpatialHash/Prefabs/Hex3DPlayer.prefab | 182 + .../Prefabs/Hex3DPlayer.prefab.meta | 14 + .../HexSpatialHash/Prefabs/SpawnPrefab.prefab | 118 + .../Prefabs/SpawnPrefab.prefab.meta | 14 + .../Examples/HexSpatialHash/Scripts.meta | 8 + .../Scripts/Hex2DNetworkManager.cs | 86 + .../Scripts/Hex2DNetworkManager.cs.meta | 18 + .../HexSpatialHash/Scripts/Hex2DPlayer.cs | 49 + .../Scripts/Hex2DPlayer.cs.meta | 18 + .../Scripts/Hex2DPlayerCamera.cs | 95 + .../Scripts/Hex2DPlayerCamera.cs.meta | 18 + .../Scripts/Hex3DNetworkManager.cs | 70 + .../Scripts/Hex3DNetworkManager.cs.meta | 18 + .../HexSpatialHash/Scripts/Hex3DPlayer.cs | 47 + .../Scripts/Hex3DPlayer.cs.meta | 18 + Assets/Mirror/Examples/LagCompensation.meta | 8 + .../Examples/LagCompensation/Capture2D.cs | 32 + .../LagCompensation/Capture2D.cs.meta | 10 + .../Examples/LagCompensation/ClientCube.cs | 240 + .../LagCompensation/ClientCube.cs.meta | 10 + .../LagCompensation/ClientMaterial.mat | 80 + .../LagCompensation/ClientMaterial.mat.meta | 15 + .../MirrorLagCompensation.unity | 483 + .../MirrorLagCompensation.unity.meta | 14 + .../Examples/LagCompensation/ServerCube.cs | 212 + .../LagCompensation/ServerCube.cs.meta | 18 + .../LagCompensation/ServerMaterial.mat | 80 + .../LagCompensation/ServerMaterial.mat.meta | 15 + .../Examples/LagCompensation/Snapshot3D.cs | 26 + .../LagCompensation/Snapshot3D.cs.meta | 18 + .../Examples/LagCompensation/_DISABLE VSYNC_ | 2 + .../LagCompensation/_DISABLE VSYNC_.meta | 14 + .../Examples/LagCompensation/_README.txt | 6 + .../Examples/LagCompensation/_README.txt.meta | 14 + Assets/Mirror/Examples/Mirror.Examples.asmdef | 19 + .../Examples/Mirror.Examples.asmdef.meta | 14 + .../Examples/MultipleAdditiveScenes.meta | 8 + .../MultipleAdditiveScenes/Materials.meta | 8 + .../Materials/Physics.meta | 8 + .../Physics/Icosphere.physicMaterial | 14 + .../Physics/Icosphere.physicMaterial.meta | 15 + .../Materials/Physics/Player.physicMaterial | 14 + .../Physics/Player.physicMaterial.meta | 15 + .../Physics/RoomBounce.physicMaterial | 14 + .../Physics/RoomBounce.physicMaterial.meta | 15 + .../Materials/Render.meta | 8 + .../Materials/Render/PlayArea.mat | 77 + .../Materials/Render/PlayArea.mat.meta | 15 + .../Materials/Render/Player.mat | 77 + .../Materials/Render/Player.mat.meta | 15 + .../Materials/Render/Prize.mat | 77 + .../Materials/Render/Prize.mat.meta | 15 + .../MultipleAdditiveScenes/Models.meta | 8 + .../Models/Icosphere.meta | 8 + .../Models/Icosphere/Icosphere.obj | 119 + .../Models/Icosphere/Icosphere.obj.meta | 111 + .../Models/Icosphere/Materials.meta | 8 + .../Models/Icosphere/Materials/Icosphere.mat | 77 + .../Icosphere/Materials/Icosphere.mat.meta | 15 + .../MultipleAdditiveScenes/Prefabs.meta | 8 + .../Prefabs/Icosphere.prefab | 233 + .../Prefabs/Icosphere.prefab.meta | 14 + .../Prefabs/PlayerReliable.prefab | 406 + .../Prefabs/PlayerReliable.prefab.meta | 15 + .../Prefabs/PlayerUnreliable.prefab | 406 + .../Prefabs/PlayerUnreliable.prefab.meta | 15 + .../Prefabs/Reward.prefab | 198 + .../Prefabs/Reward.prefab.meta | 15 + .../Examples/MultipleAdditiveScenes/README.md | 34 + .../MultipleAdditiveScenes/README.md.meta | 14 + .../MultipleAdditiveScenes/Scenes.meta | 8 + .../MirrorMultipleAdditiveScenesGame.unity | 779 + ...irrorMultipleAdditiveScenesGame.unity.meta | 14 + .../MirrorMultipleAdditiveScenesMain.meta | 8 + .../MirrorMultipleAdditiveScenesMain.unity | 878 ++ ...irrorMultipleAdditiveScenesMain.unity.meta | 14 + .../LightingData.asset | Bin 0 -> 18160 bytes .../LightingData.asset.meta | 15 + .../ReflectionProbe-0.exr | Bin 0 -> 110488 bytes .../ReflectionProbe-0.exr.meta | 99 + .../MultipleAdditiveScenes/Scripts.meta | 8 + .../Scripts/MultiSceneNetManager.cs | 179 + .../Scripts/MultiSceneNetManager.cs.meta | 18 + .../Scripts/PhysicsCollision.cs | 46 + .../Scripts/PhysicsCollision.cs.meta | 18 + .../Scripts/PlayerScore.cs | 30 + .../Scripts/PlayerScore.cs.meta | 18 + .../MultipleAdditiveScenes/Scripts/Reward.cs | 65 + .../Scripts/Reward.cs.meta | 18 + .../MultipleAdditiveScenes/Scripts/Spawner.cs | 107 + .../Scripts/Spawner.cs.meta | 18 + Assets/Mirror/Examples/MultipleMatches.meta | 8 + .../Examples/MultipleMatches/Prefabs.meta | 8 + .../MultipleMatches/Prefabs/CellGUI.prefab | 149 + .../Prefabs/CellGUI.prefab.meta | 14 + .../Prefabs/MatchController.prefab | 2172 +++ .../Prefabs/MatchController.prefab.meta | 14 + .../MultipleMatches/Prefabs/MatchGUI.prefab | 311 + .../Prefabs/MatchGUI.prefab.meta | 14 + .../Prefabs/MatchPlayer.prefab | 67 + .../Prefabs/MatchPlayer.prefab.meta | 14 + .../MultipleMatches/Prefabs/PlayerGUI.prefab | 185 + .../Prefabs/PlayerGUI.prefab.meta | 14 + .../Mirror/Examples/MultipleMatches/README.md | 9 + .../Examples/MultipleMatches/README.md.meta | 14 + .../Examples/MultipleMatches/Scenes.meta | 8 + .../Scenes/MirrorMultipleMatches.unity | 2995 ++++ .../Scenes/MirrorMultipleMatches.unity.meta | 14 + .../Examples/MultipleMatches/Scripts.meta | 8 + .../Scripts/CanvasController.cs | 644 + .../Scripts/CanvasController.cs.meta | 18 + .../MultipleMatches/Scripts/CellGUI.cs | 47 + .../MultipleMatches/Scripts/CellGUI.cs.meta | 18 + .../Scripts/MatchController.cs | 312 + .../Scripts/MatchController.cs.meta | 18 + .../MultipleMatches/Scripts/MatchGUI.cs | 48 + .../MultipleMatches/Scripts/MatchGUI.cs.meta | 18 + .../MultipleMatches/Scripts/MatchMessages.cs | 117 + .../Scripts/MatchMessages.cs.meta | 18 + .../Scripts/MatchNetworkManager.cs | 110 + .../Scripts/MatchNetworkManager.cs.meta | 18 + .../MultipleMatches/Scripts/PlayerGUI.cs | 17 + .../MultipleMatches/Scripts/PlayerGUI.cs.meta | 18 + .../MultipleMatches/Scripts/RoomGUI.cs | 45 + .../MultipleMatches/Scripts/RoomGUI.cs.meta | 18 + .../Mirror/Examples/PickupsDropsChilds.meta | 8 + .../PickupsDropsChilds/Materials.meta | 8 + .../PickupsDropsChilds/Materials/Ball.mat | 78 + .../Materials/Ball.mat.meta | 15 + .../PickupsDropsChilds/Materials/Bat.mat | 78 + .../PickupsDropsChilds/Materials/Bat.mat.meta | 15 + .../Materials/Bouncy.physicMaterial | 14 + .../Materials/Bouncy.physicMaterial.meta | 15 + .../PickupsDropsChilds/Materials/Box.mat | 78 + .../PickupsDropsChilds/Materials/Box.mat.meta | 15 + .../PickupsDropsChilds.unity | 689 + .../PickupsDropsChilds.unity.meta | 14 + .../Examples/PickupsDropsChilds/Prefabs.meta | 8 + .../PickupsDropsChilds/Prefabs/Ball.prefab | 113 + .../Prefabs/Ball.prefab.meta | 14 + .../PickupsDropsChilds/Prefabs/Bat.prefab | 114 + .../Prefabs/Bat.prefab.meta | 14 + .../PickupsDropsChilds/Prefabs/Box.prefab | 113 + .../Prefabs/Box.prefab.meta | 14 + .../Prefabs/Custom Robot Kyle.prefab | 1733 +++ .../Prefabs/Custom Robot Kyle.prefab.meta | 14 + .../PickupsDropsChilds/Prefabs/Player.prefab | 202 + .../Prefabs/Player.prefab.meta | 14 + .../Prefabs/SceneObject.prefab | 130 + .../Prefabs/SceneObject.prefab.meta | 14 + .../Examples/PickupsDropsChilds/Scripts.meta | 8 + .../Scripts/Enumerations.cs | 10 + .../Scripts/Enumerations.cs.meta | 18 + .../Scripts/Interfaces.meta | 8 + .../Scripts/Interfaces/EquippedBall.cs | 67 + .../Scripts/Interfaces/EquippedBall.cs.meta | 18 + .../Scripts/Interfaces/EquippedBat.cs | 67 + .../Scripts/Interfaces/EquippedBat.cs.meta | 18 + .../Scripts/Interfaces/EquippedBox.cs | 67 + .../Scripts/Interfaces/EquippedBox.cs.meta | 18 + .../Scripts/Interfaces/IEquipped.cs | 74 + .../Scripts/Interfaces/IEquipped.cs.meta | 18 + .../Scripts/PickupsDropsChilds.cs | 259 + .../Scripts/PickupsDropsChilds.cs.meta | 18 + .../PickupsDropsChilds/Scripts/SceneObject.cs | 108 + .../Scripts/SceneObject.cs.meta | 18 + Assets/Mirror/Examples/PlayerTest.meta | 8 + .../Examples/PlayerTest/PlayerHybrid.prefab | 491 + .../PlayerTest/PlayerHybrid.prefab.meta | 14 + .../Examples/PlayerTest/PlayerRBHybrid.prefab | 473 + .../PlayerTest/PlayerRBHybrid.prefab.meta | 14 + .../PlayerTest/PlayerRBReliable.prefab | 474 + .../PlayerTest/PlayerRBReliable.prefab.meta | 14 + .../PlayerTest/PlayerRBUnreliable.prefab | 474 + .../PlayerTest/PlayerRBUnreliable.prefab.meta | 14 + .../Examples/PlayerTest/PlayerReliable.prefab | 492 + .../PlayerTest/PlayerReliable.prefab.meta | 14 + .../Examples/PlayerTest/PlayerTestNetMan.cs | 265 + .../PlayerTest/PlayerTestNetMan.cs.meta | 18 + .../Examples/PlayerTest/PlayerTestScene.meta | 8 + .../Examples/PlayerTest/PlayerTestScene.unity | 880 ++ .../PlayerTest/PlayerTestScene.unity.meta | 14 + .../PlayerTestScene/LightingData.asset | Bin 0 -> 18360 bytes .../PlayerTestScene/LightingData.asset.meta | 15 + .../PlayerTestScene/Lightmap-0_comp_dir.png | Bin 0 -> 308048 bytes .../Lightmap-0_comp_dir.png.meta | 99 + .../PlayerTestScene/Lightmap-0_comp_light.exr | Bin 0 -> 852415 bytes .../Lightmap-0_comp_light.exr.meta | 99 + .../PlayerTestScene/ReflectionProbe-0.exr | Bin 0 -> 133554 bytes .../ReflectionProbe-0.exr.meta | 99 + .../PlayerTestScene/TerrainData2019.asset | Bin 0 -> 1952836 bytes .../TerrainData2019.asset.meta | 15 + .../TerrainLayer2019.terrainlayer | 22 + .../TerrainLayer2019.terrainlayer.meta | 15 + .../PlayerTest/PlayerUnreliable.prefab | 492 + .../PlayerTest/PlayerUnreliable.prefab.meta | 14 + .../Examples/PlayerTest/TankHybrid.prefab | 657 + .../PlayerTest/TankHybrid.prefab.meta | 14 + .../Examples/PlayerTest/TankReliable.prefab | 660 + .../PlayerTest/TankReliable.prefab.meta | 14 + .../Examples/PlayerTest/TankUnreliable.prefab | 660 + .../PlayerTest/TankUnreliable.prefab.meta | 14 + Assets/Mirror/Examples/Pong.meta | 8 + .../Examples/Pong/PhysicsMaterials.meta | 8 + .../BallMaterial.physicsMaterial2D | 10 + .../BallMaterial.physicsMaterial2D.meta | 15 + Assets/Mirror/Examples/Pong/Prefabs.meta | 8 + .../Mirror/Examples/Pong/Prefabs/Ball.prefab | 202 + .../Examples/Pong/Prefabs/Ball.prefab.meta | 15 + .../Examples/Pong/Prefabs/Racket.prefab | 202 + .../Examples/Pong/Prefabs/Racket.prefab.meta | 15 + Assets/Mirror/Examples/Pong/Scenes.meta | 8 + .../Examples/Pong/Scenes/MirrorPong.unity | 932 ++ .../Pong/Scenes/MirrorPong.unity.meta | 15 + Assets/Mirror/Examples/Pong/Scripts.meta | 8 + Assets/Mirror/Examples/Pong/Scripts/Ball.cs | 69 + .../Mirror/Examples/Pong/Scripts/Ball.cs.meta | 19 + .../Pong/Scripts/NetworkManagerPong.cs | 45 + .../Pong/Scripts/NetworkManagerPong.cs.meta | 18 + Assets/Mirror/Examples/Pong/Scripts/Player.cs | 23 + .../Examples/Pong/Scripts/Player.cs.meta | 19 + Assets/Mirror/Examples/Pong/Sprites.meta | 8 + Assets/Mirror/Examples/Pong/Sprites/Ball.png | Bin 0 -> 2791 bytes .../Examples/Pong/Sprites/Ball.png.meta | 95 + .../Examples/Pong/Sprites/DottedLine.png | Bin 0 -> 2799 bytes .../Examples/Pong/Sprites/DottedLine.png.meta | 95 + .../Mirror/Examples/Pong/Sprites/Racket.png | Bin 0 -> 2800 bytes .../Examples/Pong/Sprites/Racket.png.meta | 95 + .../Examples/Pong/Sprites/WallHorizontal.png | Bin 0 -> 2796 bytes .../Pong/Sprites/WallHorizontal.png.meta | 95 + .../Examples/Pong/Sprites/WallVertical.png | Bin 0 -> 2800 bytes .../Pong/Sprites/WallVertical.png.meta | 95 + .../Mirror/Examples/RigidbodyBenchmark.meta | 8 + .../RigidbodyBenchmark/Materials.meta | 8 + .../RigidbodyBenchmark/Materials/Floor.mat | 80 + .../Materials/Floor.mat.meta | 15 + .../RigidbodyBenchmark/Materials/Player.mat | 80 + .../Materials/Player.mat.meta | 15 + .../RigidbodyBenchmark/Materials/Server.mat | 80 + .../Materials/Server.mat.meta | 15 + .../RigidbodyBenchmark/PhysicMaterials.meta | 8 + .../PhysicMaterials/Ball.physicMaterial | 14 + .../PhysicMaterials/Ball.physicMaterial.meta | 15 + .../PhysicMaterials/Floor.physicMaterial | 14 + .../PhysicMaterials/Floor.physicMaterial.meta | 15 + .../Examples/RigidbodyBenchmark/Prefabs.meta | 8 + .../Prefabs/Player Ball.prefab | 182 + .../Prefabs/Player Ball.prefab.meta | 14 + .../Prefabs/Server Ball.prefab | 183 + .../Prefabs/Server Ball.prefab.meta | 14 + .../Examples/RigidbodyBenchmark/Scenes.meta | 8 + .../Scenes/MirrorRigidbodyBenchmark.unity | 606 + .../MirrorRigidbodyBenchmark.unity.meta | 14 + .../Examples/RigidbodyBenchmark/Scripts.meta | 8 + .../RigidbodyBenchmark/Scripts/AddForce.cs | 27 + .../Scripts/AddForce.cs.meta | 18 + .../RigidbodyBenchmark/Scripts/AutoForce.cs | 32 + .../Scripts/AutoForce.cs.meta | 18 + .../RigidbodyBenchmarkNetworkManager.cs | 52 + .../RigidbodyBenchmarkNetworkManager.cs.meta | 18 + Assets/Mirror/Examples/RigidbodyPhysics.meta | 8 + .../Examples/RigidbodyPhysics/Materials.meta | 8 + .../RigidbodyPhysics/Materials/Floor.mat | 80 + .../RigidbodyPhysics/Materials/Floor.mat.meta | 15 + .../RigidbodyPhysics/Materials/Player.mat | 80 + .../Materials/Player.mat.meta | 15 + .../RigidbodyPhysics/Materials/Server.mat | 80 + .../Materials/Server.mat.meta | 15 + .../RigidbodyPhysics/PhysicMaterials.meta | 8 + .../PhysicMaterials/Ball.physicMaterial | 14 + .../PhysicMaterials/Ball.physicMaterial.meta | 15 + .../PhysicMaterials/Floor.physicMaterial | 14 + .../PhysicMaterials/Floor.physicMaterial.meta | 15 + .../Examples/RigidbodyPhysics/Prefabs.meta | 8 + .../Prefabs/Player Ball.prefab | 182 + .../Prefabs/Player Ball.prefab.meta | 14 + .../Examples/RigidbodyPhysics/Scenes.meta | 8 + .../Scenes/MirrorBounceScene.unity | 1378 ++ .../Scenes/MirrorBounceScene.unity.meta | 14 + .../Examples/RigidbodyPhysics/Scripts.meta | 8 + .../RigidbodyPhysics/Scripts/AddForce.cs | 27 + .../RigidbodyPhysics/Scripts/AddForce.cs.meta | 18 + Assets/Mirror/Examples/Room.meta | 8 + Assets/Mirror/Examples/Room/Materials.meta | 8 + .../Examples/Room/Materials/PlayArea.mat | 77 + .../Examples/Room/Materials/PlayArea.mat.meta | 15 + .../Mirror/Examples/Room/Materials/Player.mat | 77 + .../Examples/Room/Materials/Player.mat.meta | 15 + .../Mirror/Examples/Room/Materials/Prize.mat | 77 + .../Examples/Room/Materials/Prize.mat.meta | 15 + Assets/Mirror/Examples/Room/Prefabs.meta | 8 + .../Room/Prefabs/GamePlayerReliable.prefab | 403 + .../Prefabs/GamePlayerReliable.prefab.meta | 15 + .../Room/Prefabs/GamePlayerUnreliable.prefab | 403 + .../Prefabs/GamePlayerUnreliable.prefab.meta | 15 + .../Examples/Room/Prefabs/Reward.prefab | 198 + .../Examples/Room/Prefabs/Reward.prefab.meta | 15 + .../Examples/Room/Prefabs/RoomPlayer.prefab | 69 + .../Room/Prefabs/RoomPlayer.prefab.meta | 15 + Assets/Mirror/Examples/Room/README.md | 28 + Assets/Mirror/Examples/Room/README.md.meta | 14 + Assets/Mirror/Examples/Room/Scenes.meta | 8 + .../Examples/Room/Scenes/MirrorRoomGame.meta | 8 + .../Examples/Room/Scenes/MirrorRoomGame.unity | 888 ++ .../Room/Scenes/MirrorRoomGame.unity.meta | 14 + .../Scenes/MirrorRoomGame/LightingData.asset | Bin 0 -> 18160 bytes .../MirrorRoomGame/LightingData.asset.meta | 15 + .../MirrorRoomGame/ReflectionProbe-0.exr | Bin 0 -> 110488 bytes .../MirrorRoomGame/ReflectionProbe-0.exr.meta | 99 + .../Room/Scenes/MirrorRoomOffline.unity | 330 + .../Room/Scenes/MirrorRoomOffline.unity.meta | 14 + .../Room/Scenes/MirrorRoomOnline.unity | 198 + .../Room/Scenes/MirrorRoomOnline.unity.meta | 14 + Assets/Mirror/Examples/Room/Scripts.meta | 8 + .../Room/Scripts/NetworkRoomManagerExt.cs | 110 + .../Scripts/NetworkRoomManagerExt.cs.meta | 18 + .../Room/Scripts/NetworkRoomPlayerExt.cs | 38 + .../Room/Scripts/NetworkRoomPlayerExt.cs.meta | 18 + .../Examples/Room/Scripts/PlayerScore.cs | 19 + .../Examples/Room/Scripts/PlayerScore.cs.meta | 18 + Assets/Mirror/Examples/Room/Scripts/Reward.cs | 65 + .../Examples/Room/Scripts/Reward.cs.meta | 18 + .../Mirror/Examples/Room/Scripts/Spawner.cs | 104 + .../Examples/Room/Scripts/Spawner.cs.meta | 18 + .../Examples/Snapshot Interpolation.meta | 8 + .../Snapshot Interpolation/ClientCube.cs | 221 + .../Snapshot Interpolation/ClientCube.cs.meta | 10 + .../Snapshot Interpolation/ClientMaterial.mat | 80 + .../ClientMaterial.mat.meta | 15 + .../MirrorSnapshotInterpolation.unity | 447 + .../MirrorSnapshotInterpolation.unity.meta | 14 + .../Snapshot Interpolation/README.txt | 3 + .../Snapshot Interpolation/README.txt.meta | 10 + .../Snapshot Interpolation/ServerCube.cs | 108 + .../Snapshot Interpolation/ServerCube.cs.meta | 18 + .../Snapshot Interpolation/ServerMaterial.mat | 80 + .../ServerMaterial.mat.meta | 15 + .../Snapshot Interpolation/Snapshot3D.cs | 26 + .../Snapshot Interpolation/Snapshot3D.cs.meta | 18 + .../Snapshot Interpolation/_DISABLE VSYNC_ | 2 + .../_DISABLE VSYNC_.meta | 14 + Assets/Mirror/Examples/StackedPrediction.meta | 8 + .../StackedPrediction/CubeMaterial.mat | 81 + .../StackedPrediction/CubeMaterial.mat.meta | 15 + .../CubeMaterial.physicMaterial | 14 + .../CubeMaterial.physicMaterial.meta | 15 + .../StackedPrediction/GroundMaterial.mat | 82 + .../StackedPrediction/GroundMaterial.mat.meta | 15 + .../MirrorStackedPrediction.unity | 554 + .../MirrorStackedPrediction.unity.meta | 14 + .../NetworkManagerStackedPrediction.cs | 83 + .../NetworkManagerStackedPrediction.cs.meta | 18 + .../Examples/StackedPrediction/PlayerForce.cs | 47 + .../StackedPrediction/PlayerForce.cs.meta | 10 + .../StackedPrediction/PlayerSpectator.prefab | 67 + .../PlayerSpectator.prefab.meta | 14 + .../StackedPrediction/PredictedCube.prefab | 168 + .../PredictedCube.prefab.meta | 14 + .../Examples/StackedPrediction/_Readme.txt | 17 + .../StackedPrediction/_Readme.txt.meta | 10 + Assets/Mirror/Examples/SyncDirection.meta | 8 + .../SyncDirection/MirrorSyncDirection.unity | 618 + .../MirrorSyncDirection.unity.meta | 14 + .../Mirror/Examples/SyncDirection/Player.cs | 58 + .../Examples/SyncDirection/Player.cs.meta | 18 + .../Examples/SyncDirection/Player.prefab | 212 + .../Examples/SyncDirection/Player.prefab.meta | 14 + .../Mirror/Examples/SyncDirection/White.mat | 77 + .../Examples/SyncDirection/White.mat.meta | 15 + Assets/Mirror/Examples/TankTheftAuto.meta | 8 + .../Examples/TankTheftAuto/Materials.meta | 8 + .../Materials/MaterialPlayer.mat | 77 + .../Materials/MaterialPlayer.mat.meta | 15 + .../Materials/MaterialTrigger.mat | 78 + .../Materials/MaterialTrigger.mat.meta | 15 + .../TankTheftAuto/MirrorTankTheftAuto.meta | 8 + .../TankTheftAuto/MirrorTankTheftAuto.unity | 982 ++ .../MirrorTankTheftAuto.unity.meta | 14 + .../MirrorTankTheftAuto/LightingData.asset | Bin 0 -> 18136 bytes .../LightingData.asset.meta | 15 + .../Examples/TankTheftAuto/Prefabs.meta | 8 + .../Prefabs/PlayerReliable.prefab | 385 + .../Prefabs/PlayerReliable.prefab.meta | 14 + .../Prefabs/PlayerUnreliable.prefab | 385 + .../Prefabs/PlayerUnreliable.prefab.meta | 14 + .../TankTheftAuto/Prefabs/TankReliable.prefab | 886 ++ .../Prefabs/TankReliable.prefab.meta | 14 + .../Prefabs/TankUnreliable.prefab | 886 ++ .../Prefabs/TankUnreliable.prefab.meta | 14 + .../Examples/TankTheftAuto/Scripts.meta | 8 + .../TankTheftAuto/Scripts/TankAuthority.cs | 143 + .../Scripts/TankAuthority.cs.meta | 18 + .../Scripts/TankTheftAutoNetMan.cs | 30 + .../Scripts/TankTheftAutoNetMan.cs.meta | 18 + Assets/Mirror/Examples/Tanks.meta | 8 + Assets/Mirror/Examples/Tanks/Prefabs.meta | 8 + .../Examples/Tanks/Prefabs/Projectile.prefab | 181 + .../Tanks/Prefabs/Projectile.prefab.meta | 14 + .../Mirror/Examples/Tanks/Prefabs/Tank.prefab | 363 + .../Examples/Tanks/Prefabs/Tank.prefab.meta | 15 + Assets/Mirror/Examples/Tanks/Readme.txt | 2 + Assets/Mirror/Examples/Tanks/Readme.txt.meta | 10 + Assets/Mirror/Examples/Tanks/Scenes.meta | 8 + .../Examples/Tanks/Scenes/MirrorTanks.meta | 8 + .../Examples/Tanks/Scenes/MirrorTanks.unity | 713 + .../Tanks/Scenes/MirrorTanks.unity.meta | 14 + .../Tanks/Scenes/MirrorTanks/NavMesh.asset | Bin 0 -> 6564 bytes .../Scenes/MirrorTanks/NavMesh.asset.meta | 15 + Assets/Mirror/Examples/Tanks/Scripts.meta | 8 + Assets/Mirror/Examples/Tanks/Scripts/Box.cs | 94 + .../Mirror/Examples/Tanks/Scripts/Box.cs.meta | 18 + .../Examples/Tanks/Scripts/Projectile.cs | 46 + .../Examples/Tanks/Scripts/Projectile.cs.meta | 18 + Assets/Mirror/Examples/Tanks/Scripts/Tank.cs | 106 + .../Examples/Tanks/Scripts/Tank.cs.meta | 18 + Assets/Mirror/Examples/TopDownShooter.meta | 8 + .../Examples/TopDownShooter/Materials.meta | 8 + .../Materials/DeathSplatter.mat | 78 + .../Materials/DeathSplatter.mat.meta | 15 + .../TopDownShooter/Materials/Enemy.mat | 78 + .../TopDownShooter/Materials/Enemy.mat.meta | 15 + .../TopDownShooter/Materials/EnemyHand1.mat | 78 + .../Materials/EnemyHand1.mat.meta | 15 + .../TopDownShooter/Materials/EnemyHand2.mat | 78 + .../Materials/EnemyHand2.mat.meta | 15 + .../TopDownShooter/Materials/Flash.mat | 78 + .../TopDownShooter/Materials/Flash.mat.meta | 15 + .../TopDownShooter/Materials/Floor.mat | 83 + .../TopDownShooter/Materials/Floor.mat.meta | 15 + .../TopDownShooter/Materials/HitPoint.mat | 78 + .../Materials/HitPoint.mat.meta | 15 + .../Materials/MaterialBlack.mat | 83 + .../Materials/MaterialBlack.mat.meta | 15 + .../TopDownShooter/Materials/MaterialGrey.mat | 83 + .../Materials/MaterialGrey.mat.meta | 15 + .../Materials/MaterialWalls.mat | 77 + .../Materials/MaterialWalls.mat.meta | 15 + .../Materials/MaterialYellow.mat | 83 + .../Materials/MaterialYellow.mat.meta | 15 + .../TopDownShooter/Materials/Player.mat | 78 + .../TopDownShooter/Materials/Player.mat.meta | 15 + .../TopDownShooter/Materials/PlayerLF.mat | 78 + .../Materials/PlayerLF.mat.meta | 15 + .../TopDownShooter/Materials/PlayerRF.mat | 78 + .../Materials/PlayerRF.mat.meta | 15 + .../Materials/RespawnPortal.mat | 78 + .../Materials/RespawnPortal.mat.meta | 15 + .../Examples/TopDownShooter/Prefabs.meta | 8 + .../Prefabs/DeathSplatter.prefab | 240 + .../Prefabs/DeathSplatter.prefab.meta | 14 + .../TopDownShooter/Prefabs/EnemyPrefab.prefab | 928 ++ .../Prefabs/EnemyPrefab.prefab.meta | 14 + .../Prefabs/PlayerPrefab.prefab | 2066 +++ .../Prefabs/PlayerPrefab.prefab.meta | 14 + .../Examples/TopDownShooter/Scenes.meta | 8 + .../Scenes/MirrorTopDownShooter.meta | 8 + .../Scenes/MirrorTopDownShooter.unity | 5435 +++++++ .../Scenes/MirrorTopDownShooter.unity.meta | 14 + .../MirrorTopDownShooter/LightingData.asset | Bin 0 -> 18160 bytes .../LightingData.asset.meta | 15 + .../Scenes/MirrorTopDownShooter/NavMesh.asset | Bin 0 -> 9348 bytes .../MirrorTopDownShooter/NavMesh.asset.meta | 15 + .../ReflectionProbe-0.exr | Bin 0 -> 138601 bytes .../ReflectionProbe-0.exr.meta | 99 + .../Examples/TopDownShooter/Scripts.meta | 8 + .../TopDownShooter/Scripts/CameraTopDown.cs | 22 + .../Scripts/CameraTopDown.cs.meta | 18 + .../TopDownShooter/Scripts/CanvasHUD.cs | 224 + .../TopDownShooter/Scripts/CanvasHUD.cs.meta | 18 + .../TopDownShooter/Scripts/CanvasTopDown.cs | 97 + .../Scripts/CanvasTopDown.cs.meta | 18 + .../TopDownShooter/Scripts/EnemyTopDown.cs | 183 + .../Scripts/EnemyTopDown.cs.meta | 18 + .../TopDownShooter/Scripts/NetworkTopDown.cs | 66 + .../Scripts/NetworkTopDown.cs.meta | 18 + .../TopDownShooter/Scripts/PlayerTopDown.cs | 338 + .../Scripts/PlayerTopDown.cs.meta | 18 + .../TopDownShooter/Scripts/RespawnPortal.cs | 52 + .../Scripts/RespawnPortal.cs.meta | 18 + .../Examples/TopDownShooter/Textures.meta | 8 + .../TopDownShooter/Textures/CornerUI.png | Bin 0 -> 18986 bytes .../TopDownShooter/Textures/CornerUI.png.meta | 160 + .../TopDownShooter/Textures/DeathSplatter.png | Bin 0 -> 80253 bytes .../Textures/DeathSplatter.png.meta | 160 + .../TopDownShooter/Textures/Enemy.png | Bin 0 -> 104644 bytes .../TopDownShooter/Textures/Enemy.png.meta | 160 + .../TopDownShooter/Textures/EnemyHand1.png | Bin 0 -> 29523 bytes .../Textures/EnemyHand1.png.meta | 160 + .../TopDownShooter/Textures/EnemyHand2.png | Bin 0 -> 30621 bytes .../Textures/EnemyHand2.png.meta | 160 + .../TopDownShooter/Textures/Flash.png | Bin 0 -> 40613 bytes .../TopDownShooter/Textures/Flash.png.meta | 160 + .../TopDownShooter/Textures/Floor.jpg | Bin 0 -> 25987 bytes .../TopDownShooter/Textures/Floor.jpg.meta | 160 + .../TopDownShooter/Textures/HitPoint.png | Bin 0 -> 107018 bytes .../TopDownShooter/Textures/HitPoint.png.meta | 160 + .../TopDownShooter/Textures/Player.png | Bin 0 -> 55932 bytes .../TopDownShooter/Textures/Player.png.meta | 160 + .../Textures/PlayerFootLeft.png | Bin 0 -> 12187 bytes .../Textures/PlayerFootLeft.png.meta | 160 + .../Textures/PlayerFootRight.png | Bin 0 -> 12136 bytes .../Textures/PlayerFootRight.png.meta | 160 + .../TopDownShooter/Textures/RespawnPortal.png | Bin 0 -> 196907 bytes .../Textures/RespawnPortal.png.meta | 160 + Assets/Mirror/Examples/VR.meta | 8 + Assets/Mirror/Examples/VR/Readme.txt | 5 + Assets/Mirror/Examples/VR/Readme.txt.meta | 10 + Assets/Mirror/Examples/_Common.meta | 8 + .../Mirror/Examples/_Common/Controllers.meta | 8 + .../_Common/Controllers/ControllerUIBase.cs | 180 + .../Controllers/ControllerUIBase.cs.meta | 18 + .../_Common/Controllers/FlyerController.meta | 8 + .../FlyerController/FlyerControllerBase.cs | 575 + .../FlyerControllerBase.cs.meta | 18 + .../FlyerControllerReliable.cs | 8 + .../FlyerControllerReliable.cs.meta | 18 + .../FlyerController/FlyerControllerUI.cs | 67 + .../FlyerController/FlyerControllerUI.cs.meta | 18 + .../FlyerController/FlyerControllerUI.prefab | 4109 ++++++ .../FlyerControllerUI.prefab.meta | 14 + .../FlyerControllerUnreliable.cs | 8 + .../FlyerControllerUnreliable.cs.meta | 18 + .../_Common/Controllers/PlayerController.meta | 8 + .../PlayerController/PlayerControllerBase.cs | 477 + .../PlayerControllerBase.cs.meta | 18 + .../PlayerControllerHybrid.cs | 8 + .../PlayerControllerHybrid.cs.meta | 18 + .../PlayerControllerReliable.cs | 8 + .../PlayerControllerReliable.cs.meta | 18 + .../PlayerController/PlayerControllerUI.cs | 51 + .../PlayerControllerUI.cs.meta | 18 + .../PlayerControllerUI.prefab | 2740 ++++ .../PlayerControllerUI.prefab.meta | 14 + .../PlayerControllerUnreliable.cs | 8 + .../PlayerControllerUnreliable.cs.meta | 18 + .../Controllers/PlayerControllerRB.meta | 8 + .../PlayerControllerRBBase.cs | 511 + .../PlayerControllerRBBase.cs.meta | 18 + .../PlayerControllerRBHybrid.cs | 23 + .../PlayerControllerRBHybrid.cs.meta | 18 + .../PlayerControllerRBReliable.cs | 23 + .../PlayerControllerRBReliable.cs.meta | 18 + .../PlayerControllerRBUI.cs | 51 + .../PlayerControllerRBUI.cs.meta | 18 + .../PlayerControllerRBUI.prefab | 2740 ++++ .../PlayerControllerRBUI.prefab.meta | 14 + .../PlayerControllerRBUnreliable.cs | 23 + .../PlayerControllerRBUnreliable.cs.meta | 18 + .../_Common/Controllers/TankController.meta | 8 + .../TankController/TankControllerBase.cs | 336 + .../TankController/TankControllerBase.cs.meta | 18 + .../TankController/TankControllerHybrid.cs | 8 + .../TankControllerHybrid.cs.meta | 18 + .../TankController/TankControllerReliable.cs | 8 + .../TankControllerReliable.cs.meta | 18 + .../TankController/TankControllerUI.cs | 54 + .../TankController/TankControllerUI.cs.meta | 18 + .../TankController/TankControllerUI.prefab | 2272 +++ .../TankControllerUI.prefab.meta | 14 + .../TankControllerUnreliable.cs | 8 + .../TankControllerUnreliable.cs.meta | 18 + .../Controllers/TankController/TankHealth.cs | 83 + .../TankController/TankHealth.cs.meta | 18 + .../TankController/TankTurretBase.cs | 468 + .../TankController/TankTurretBase.cs.meta | 18 + .../TankController/TankTurretHybrid.cs | 60 + .../TankController/TankTurretHybrid.cs.meta | 18 + .../TankController/TankTurretReliable.cs | 60 + .../TankController/TankTurretReliable.cs.meta | 18 + .../TankController/TankTurretUnreliable.cs | 60 + .../TankTurretUnreliable.cs.meta | 18 + .../Controllers/TankController/TurretUI.cs | 31 + .../TankController/TurretUI.cs.meta | 18 + .../TankController/TurretUI.prefab | 1527 ++ .../TankController/TurretUI.prefab.meta | 14 + .../Mirror/Examples/_Common/KenneyAssets.meta | 8 + .../KenneyAssets/kenney_kenney-fonts.meta | 8 + .../kenney_kenney-fonts/Fonts.meta | 8 + .../kenney_kenney-fonts/Fonts/Kenney Mini.ttf | Bin 0 -> 26156 bytes .../Fonts/Kenney Mini.ttf.meta | 29 + .../kenney_kenney-fonts/License.txt | 22 + .../kenney_kenney-fonts/License.txt.meta | 14 + .../KenneyAssets/kenney_rpg-audio.meta | 8 + .../KenneyAssets/kenney_rpg-audio/Audio.meta | 8 + .../kenney_rpg-audio/Audio/footstep06.ogg | Bin 0 -> 9885 bytes .../Audio/footstep06.ogg.meta | 30 + .../kenney_rpg-audio/Audio/footstep09.ogg | Bin 0 -> 9356 bytes .../Audio/footstep09.ogg.meta | 30 + .../KenneyAssets/kenney_rpg-audio/License.txt | 21 + .../kenney_rpg-audio/License.txt.meta | 14 + .../Mirror/Examples/_Common/OpenGameArt.meta | 8 + .../Examples/_Common/OpenGameArt/License.txt | 6 + .../_Common/OpenGameArt/License.txt.meta | 14 + .../Examples/_Common/OpenGameArt/Sounds.meta | 8 + .../Sounds/05._damage_grunt_male.mp3 | Bin 0 -> 4241 bytes .../Sounds/05._damage_grunt_male.mp3.meta | 30 + .../Sounds/8bit_gunloop_explosion.mp3 | Bin 0 -> 1913 bytes .../Sounds/8bit_gunloop_explosion.mp3.meta | 30 + .../Sounds/Light Switch Click On Sfx.mp3 | Bin 0 -> 2004 bytes .../Sounds/Light Switch Click On Sfx.mp3.meta | 31 + .../Sounds/The Good Fight (just intro).mp3 | Bin 0 -> 27452 bytes .../The Good Fight (just intro).mp3.meta | 31 + .../Sounds/The Good Fight (no intro).mp3 | Bin 0 -> 374246 bytes .../Sounds/The Good Fight (no intro).mp3.meta | 31 + .../Sounds/hjm-tesla_sound_shot.mp3 | Bin 0 -> 4590 bytes .../Sounds/hjm-tesla_sound_shot.mp3.meta | 30 + .../OpenGameArt/Sounds/impactsplat03.mp3 | Bin 0 -> 6755 bytes .../OpenGameArt/Sounds/impactsplat03.mp3.meta | 30 + .../_Common/OpenGameArt/Sounds/mutantdie.mp3 | Bin 0 -> 6971 bytes .../OpenGameArt/Sounds/mutantdie.mp3.meta | 30 + .../OpenGameArt/Sounds/vgmenuhighlight.mp3 | Bin 0 -> 1458 bytes .../Sounds/vgmenuhighlight.mp3.meta | 30 + .../OpenGameArt/Sounds/wolf_monster.mp3 | Bin 0 -> 13942 bytes .../OpenGameArt/Sounds/wolf_monster.mp3.meta | 30 + .../Mirror/Examples/_Common/Projectiles.meta | 8 + .../_Common/Projectiles/TankProjectile.meta | 8 + .../TankProjectile/TankProjectile.cs | 58 + .../TankProjectile/TankProjectile.cs.meta | 18 + .../TankProjectile/TankProjectile.mat | 80 + .../TankProjectile/TankProjectile.mat.meta | 15 + .../TankProjectile/TankProjectile.prefab | 161 + .../TankProjectile/TankProjectile.prefab.meta | 14 + Assets/Mirror/Examples/_Common/RobotKyle.meta | 8 + .../Examples/_Common/RobotKyle/Materials.meta | 7 + .../RobotKyle/Materials/Robot_Color.mat | 93 + .../RobotKyle/Materials/Robot_Color.mat.meta | 11 + .../Examples/_Common/RobotKyle/Models.meta | 7 + .../_Common/RobotKyle/Models/Robot Kyle.fbx | Bin 0 -> 330704 bytes .../RobotKyle/Models/Robot Kyle.fbx.meta | 810 ++ .../_Common/RobotKyle/Robot Kyle.prefab | 1702 +++ .../_Common/RobotKyle/Robot Kyle.prefab.meta | 14 + .../Examples/_Common/RobotKyle/Textures.meta | 7 + .../RobotKyle/Textures/Robot_Color.jpeg | Bin 0 -> 494045 bytes .../RobotKyle/Textures/Robot_Color.jpeg.meta | 111 + .../RobotKyle/Textures/Robot_Normal.jpeg | Bin 0 -> 441267 bytes .../RobotKyle/Textures/Robot_Normal.jpeg.meta | 111 + Assets/Mirror/Examples/_Common/Scripts.meta | 8 + .../Scripts/CanvasNetworkManagerHUD.meta | 8 + .../CanvasNetworkManagerHUD.cs | 233 + .../CanvasNetworkManagerHUD.cs.meta | 18 + .../CanvasNetworkManagerHUD.prefab | 1897 +++ .../CanvasNetworkManagerHUD.prefab.meta | 14 + Assets/Mirror/Examples/_Common/Scripts/FPS.cs | 38 + .../Examples/_Common/Scripts/FPS.cs.meta | 18 + .../Examples/_Common/Scripts/FaceCamera.cs | 15 + .../_Common/Scripts/FaceCamera.cs.meta | 18 + .../Examples/_Common/Scripts/PerlinNoise.cs | 52 + .../_Common/Scripts/PerlinNoise.cs.meta | 18 + .../_Common/Scripts/PhysicsSimulator.meta | 8 + .../PhysicsSimulator/PhysicsSimulator.cs | 40 + .../PhysicsSimulator/PhysicsSimulator.cs.meta | 18 + .../PhysicsSimulator/PhysicsSimulator.prefab | 45 + .../PhysicsSimulator.prefab.meta | 14 + .../Examples/_Common/Scripts/PlayerCamera.cs | 77 + .../_Common/Scripts/PlayerCamera.cs.meta | 18 + .../Examples/_Common/Scripts/RandomColor.cs | 35 + .../_Common/Scripts/RandomColor.cs.meta | 18 + .../Examples/_Common/Scripts/Respawn.cs | 47 + .../Examples/_Common/Scripts/Respawn.cs.meta | 18 + Assets/Mirror/Examples/_Common/TankModel.meta | 8 + .../TankModel/(Public Domain) Recon_Tank.meta | 8 + .../(Public Domain) Recon_Tank/BaseColor.png | Bin 0 -> 939498 bytes .../BaseColor.png.meta | 95 + .../Controller.controller | 298 + .../Controller.controller.meta | 15 + .../(Public Domain) Recon_Tank/Emissive.png | Bin 0 -> 80294 bytes .../Emissive.png.meta | 95 + .../(Public Domain) Recon_Tank/Metallic.png | Bin 0 -> 62860 bytes .../Metallic.png.meta | 95 + .../(Public Domain) Recon_Tank/Normal.png | Bin 0 -> 666342 bytes .../Normal.png.meta | 95 + .../Recon_Tank - License.txt | 7 + .../Recon_Tank - License.txt.meta | 15 + .../TankMaterial.mat | 82 + .../TankMaterial.mat.meta | 15 + .../(Public Domain) Recon_Tank/reconTank.fbx | Bin 0 -> 224204 bytes .../reconTank.fbx.meta | 340 + .../_Common/TankModel/BasePrefab.prefab | 395 + .../_Common/TankModel/BasePrefab.prefab.meta | 14 + Assets/Mirror/Examples/_Common/Textures.meta | 8 + ...lic Domain) Dirt Hand Painted Texture.meta | 8 + .../Dirt Hand Painted Texture - License.txt | 5 + ...rt Hand Painted Texture - License.txt.meta | 15 + .../Dirt.mat | 82 + .../Dirt.mat.meta | 16 + .../dirt.png | Bin 0 -> 105829 bytes .../dirt.png.meta | 96 + .../Examples/_Common/Textures/Wall01.jpg | Bin 0 -> 60894 bytes .../Examples/_Common/Textures/Wall01.jpg.meta | 99 + .../Examples/_Common/Textures/Wall01_n.jpg | Bin 0 -> 33321 bytes .../_Common/Textures/Wall01_n.jpg.meta | 99 + Assets/Mirror/Hosting.meta | 8 + Assets/Mirror/Hosting/Edgegap.meta | 8 + Assets/Mirror/Hosting/Edgegap/CHANGELOG.md | 3 + .../Mirror/Hosting/Edgegap/CHANGELOG.md.meta | 14 + .../Mirror/Hosting/Edgegap/Dependencies.meta | 8 + .../Edgegap/Dependencies/HttpEncoder.cs | 704 + .../Edgegap/Dependencies/HttpEncoder.cs.meta | 10 + .../Edgegap/Dependencies/HttpUtility.cs | 230 + .../Edgegap/Dependencies/HttpUtility.cs.meta | 10 + Assets/Mirror/Hosting/Edgegap/Edgegap.asmdef | 22 + .../Hosting/Edgegap/Edgegap.asmdef.meta | 14 + Assets/Mirror/Hosting/Edgegap/Editor.meta | 8 + Assets/Mirror/Hosting/Edgegap/Editor/Api.meta | 8 + .../Edgegap/Editor/Api/EdgegapApiBase.cs | 298 + .../Edgegap/Editor/Api/EdgegapApiBase.cs.meta | 18 + .../Edgegap/Editor/Api/EdgegapAppApi.cs | 188 + .../Edgegap/Editor/Api/EdgegapAppApi.cs.meta | 18 + .../Editor/Api/EdgegapDeploymentsApi.cs | 206 + .../Editor/Api/EdgegapDeploymentsApi.cs.meta | 18 + .../Edgegap/Editor/Api/EdgegapIpApi.cs | 42 + .../Edgegap/Editor/Api/EdgegapIpApi.cs.meta | 18 + .../Edgegap/Editor/Api/EdgegapWizardApi.cs | 52 + .../Editor/Api/EdgegapWizardApi.cs.meta | 18 + .../Hosting/Edgegap/Editor/Api/Models.meta | 8 + .../Edgegap/Editor/Api/Models/AppPortsData.cs | 28 + .../Editor/Api/Models/AppPortsData.cs.meta | 18 + .../Editor/Api/Models/DeploymentPortsData.cs | 29 + .../Api/Models/DeploymentPortsData.cs.meta | 10 + .../Edgegap/Editor/Api/Models/LocationData.cs | 28 + .../Editor/Api/Models/LocationData.cs.meta | 18 + .../Edgegap/Editor/Api/Models/ProtocolType.cs | 18 + .../Editor/Api/Models/ProtocolType.cs.meta | 18 + .../Edgegap/Editor/Api/Models/Requests.meta | 8 + .../Api/Models/Requests/CreateAppRequest.cs | 55 + .../Models/Requests/CreateAppRequest.cs.meta | 18 + .../Requests/CreateAppVersionRequest.cs | 225 + .../Requests/CreateAppVersionRequest.cs.meta | 18 + .../Requests/CreateDeploymentRequest.cs | 62 + .../Requests/CreateDeploymentRequest.cs.meta | 18 + .../Requests/UpdateAppVersionRequest.cs | 175 + .../Requests/UpdateAppVersionRequest.cs.meta | 18 + .../Edgegap/Editor/Api/Models/Results.meta | 8 + .../Models/Results/CreateDeploymentResult.cs | 53 + .../Results/CreateDeploymentResult.cs.meta | 18 + .../Api/Models/Results/EdgegapErrorResult.cs | 12 + .../Models/Results/EdgegapErrorResult.cs.meta | 18 + .../Api/Models/Results/EdgegapHttpResult.cs | 120 + .../Models/Results/EdgegapHttpResult.cs.meta | 18 + .../Models/Results/GetAppVersionsResult.cs | 15 + .../Results/GetAppVersionsResult.cs.meta | 18 + .../Api/Models/Results/GetAppsResult.cs | 15 + .../Api/Models/Results/GetAppsResult.cs.meta | 18 + .../Api/Models/Results/GetCreateAppResult.cs | 31 + .../Models/Results/GetCreateAppResult.cs.meta | 18 + .../Api/Models/Results/GetDeploymentResult.cs | 20 + .../Results/GetDeploymentResult.cs.meta | 18 + .../Results/GetDeploymentStatusResult.cs | 89 + .../Results/GetDeploymentStatusResult.cs.meta | 18 + .../Models/Results/GetDeploymentsResult.cs | 14 + .../Results/GetDeploymentsResult.cs.meta | 18 + .../Results/GetRegistryCredentialsResult.cs | 22 + .../GetRegistryCredentialsResult.cs.meta | 18 + .../Models/Results/GetYourPublicIpResult.cs | 14 + .../Results/GetYourPublicIpResult.cs.meta | 18 + .../Results/StopActiveDeploymentResult.cs | 84 + .../StopActiveDeploymentResult.cs.meta | 18 + .../Models/Results/UpsertAppVersionResult.cs | 165 + .../Results/UpsertAppVersionResult.cs.meta | 18 + .../Edgegap/Editor/Api/Models/SessionData.cs | 28 + .../Editor/Api/Models/SessionData.cs.meta | 18 + .../Edgegap/Editor/Api/Models/VersionData.cs | 13 + .../Editor/Api/Models/VersionData.cs.meta | 18 + .../Hosting/Edgegap/Editor/ButtonShaker.cs | 37 + .../Edgegap/Editor/ButtonShaker.cs.meta | 18 + .../Edgegap/Editor/CustomPopupContent.cs | 70 + .../Edgegap/Editor/CustomPopupContent.cs.meta | 18 + .../Mirror/Hosting/Edgegap/Editor/Dockerfile | 17 + .../Hosting/Edgegap/Editor/Dockerfile.meta | 14 + .../Edgegap/Editor/EdgegapBuildUtils.cs | 452 + .../Edgegap/Editor/EdgegapBuildUtils.cs.meta | 18 + .../Edgegap/Editor/EdgegapServerData.uss | 81 + .../Edgegap/Editor/EdgegapServerData.uss.meta | 18 + .../Editor/EdgegapServerDataManager.cs | 248 + .../Editor/EdgegapServerDataManager.cs.meta | 18 + .../Hosting/Edgegap/Editor/EdgegapWindow.uss | 298 + .../Edgegap/Editor/EdgegapWindow.uss.meta | 18 + .../Hosting/Edgegap/Editor/EdgegapWindow.uxml | 163 + .../Edgegap/Editor/EdgegapWindow.uxml.meta | 17 + .../Edgegap/Editor/EdgegapWindowMetadata.cs | 243 + .../Editor/EdgegapWindowMetadata.cs.meta | 18 + .../Hosting/Edgegap/Editor/EdgegapWindowV2.cs | 2472 ++++ .../Edgegap/Editor/EdgegapWindowV2.cs.meta | 18 + .../Mirror/Hosting/Edgegap/Editor/Fonts.meta | 8 + .../Edgegap/Editor/Fonts/BaronNeue SDF.asset | 2660 ++++ .../Editor/Fonts/BaronNeue SDF.asset.meta | 15 + .../Editor/Fonts/Spartan-Regular SDF.asset | 2727 ++++ .../Fonts/Spartan-Regular SDF.asset.meta | 15 + .../Editor/Fonts/Spartan-SemiBold SDF.asset | 2739 ++++ .../Fonts/Spartan-SemiBold SDF.asset.meta | 15 + .../Hosting/Edgegap/Editor/Fonts/Src.meta | 8 + .../Edgegap/Editor/Fonts/Src/BaronNeue.otf | Bin 0 -> 27176 bytes .../Editor/Fonts/Src/BaronNeue.otf.meta | 28 + .../Edgegap/Editor/Fonts/Src/Spartan.meta | 8 + .../Fonts/Src/Spartan/Spartan-Regular.ttf | Bin 0 -> 38384 bytes .../Src/Spartan/Spartan-Regular.ttf.meta | 28 + .../Fonts/Src/Spartan/Spartan-SemiBold.ttf | Bin 0 -> 38392 bytes .../Src/Spartan/Spartan-SemiBold.ttf.meta | 28 + .../Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf | Bin 0 -> 205748 bytes .../Editor/Fonts/Src/UbuntuMono-R.ttf.meta | 28 + .../Editor/Fonts/UbuntuMono-R SDF.asset | 2723 ++++ .../Editor/Fonts/UbuntuMono-R SDF.asset.meta | 15 + .../Hosting/Edgegap/Editor/GithubRelease.cs | 31 + .../Edgegap/Editor/GithubRelease.cs.meta | 18 + .../Mirror/Hosting/Edgegap/Editor/Images.meta | 8 + .../Edgegap/Editor/Images/clipboard-128.png | Bin 0 -> 3083 bytes .../Editor/Images/clipboard-128.png.meta | 147 + .../Images/discord-brands-solid-64px.png | Bin 0 -> 1607 bytes .../Images/discord-brands-solid-64px.png.meta | 147 + .../Editor/Images/discord-brands-solid.svg | 1 + .../Images/discord-brands-solid.svg.meta | 61 + .../Images/logo_transparent_400_alpha25.png | Bin 0 -> 13034 bytes .../logo_transparent_400_alpha25.png.meta | 103 + .../Hosting/Edgegap/Editor/PackageJSON.cs | 37 + .../Edgegap/Editor/PackageJSON.cs.meta | 18 + Assets/Mirror/Hosting/Edgegap/Enums.meta | 8 + .../Hosting/Edgegap/Enums/ApiEnvironment.cs | 71 + .../Edgegap/Enums/ApiEnvironment.cs.meta | 18 + .../Hosting/Edgegap/Enums/ServerStatus.cs | 84 + .../Edgegap/Enums/ServerStatus.cs.meta | 18 + .../Mirror/Hosting/Edgegap/Enums/ToolState.cs | 46 + .../Hosting/Edgegap/Enums/ToolState.cs.meta | 18 + Assets/Mirror/Hosting/Edgegap/LICENSE.md | 21 + Assets/Mirror/Hosting/Edgegap/LICENSE.md.meta | 14 + Assets/Mirror/Hosting/Edgegap/Models.meta | 8 + .../Models/AppVersionUpdatePatchData.cs | 24 + .../Models/AppVersionUpdatePatchData.cs.meta | 18 + .../Hosting/Edgegap/Models/DeployPostData.cs | 24 + .../Edgegap/Models/DeployPostData.cs.meta | 18 + Assets/Mirror/Hosting/Edgegap/Models/SDK.meta | 8 + .../Models/SDK/ApiModelContainercrashdata.cs | 63 + .../SDK/ApiModelContainercrashdata.cs.meta | 18 + .../Models/SDK/ApiModelContainerlogs.cs | 71 + .../Models/SDK/ApiModelContainerlogs.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/AppCreation.cs | 53 + .../Edgegap/Models/SDK/AppCreation.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/AppVersion.cs | 240 + .../Edgegap/Models/SDK/AppVersion.cs.meta | 18 + .../SDK/AppVersionCreateSessionConfig.cs | 81 + .../SDK/AppVersionCreateSessionConfig.cs.meta | 18 + .../Edgegap/Models/SDK/AppVersionEnv.cs | 63 + .../Edgegap/Models/SDK/AppVersionEnv.cs.meta | 18 + .../Edgegap/Models/SDK/AppVersionPort.cs | 81 + .../Edgegap/Models/SDK/AppVersionPort.cs.meta | 18 + .../Edgegap/Models/SDK/AppVersionProbe.cs | 54 + .../Models/SDK/AppVersionProbe.cs.meta | 18 + .../Edgegap/Models/SDK/AppVersionUpdate.cs | 240 + .../Models/SDK/AppVersionUpdate.cs.meta | 18 + .../SDK/AppVersionUpdateSessionConfig.cs | 81 + .../SDK/AppVersionUpdateSessionConfig.cs.meta | 18 + .../Models/SDK/AppVersionWhitelistEntry.cs | 72 + .../SDK/AppVersionWhitelistEntry.cs.meta | 18 + .../SDK/AppVersionWhitelistEntryPayload.cs | 63 + .../AppVersionWhitelistEntryPayload.cs.meta | 18 + .../SDK/AppVersionWhitelistEntrySuccess.cs | 53 + .../AppVersionWhitelistEntrySuccess.cs.meta | 18 + .../Models/SDK/AppVersionWhitelistResponse.cs | 44 + .../SDK/AppVersionWhitelistResponse.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/AppVersions.cs | 52 + .../Edgegap/Models/SDK/AppVersions.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Application.cs | 81 + .../Edgegap/Models/SDK/Application.cs.meta | 18 + .../Edgegap/Models/SDK/ApplicationPatch.cs | 63 + .../Models/SDK/ApplicationPatch.cs.meta | 18 + .../Edgegap/Models/SDK/ApplicationPost.cs | 63 + .../Models/SDK/ApplicationPost.cs.meta | 18 + .../Edgegap/Models/SDK/Applications.cs | 44 + .../Edgegap/Models/SDK/Applications.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/BaseModel.cs | 52 + .../Edgegap/Models/SDK/BaseModel.cs.meta | 18 + .../Edgegap/Models/SDK/BulkSessionDelete.cs | 54 + .../Models/SDK/BulkSessionDelete.cs.meta | 18 + .../Edgegap/Models/SDK/BulkSessionPost.cs | 54 + .../Models/SDK/BulkSessionPost.cs.meta | 18 + .../Models/SDK/ComponentCredentials.cs | 54 + .../Models/SDK/ComponentCredentials.cs.meta | 18 + .../Models/SDK/ContainerLogStorageModel.cs | 54 + .../SDK/ContainerLogStorageModel.cs.meta | 18 + .../Models/SDK/CustomBulkSessionModel.cs | 54 + .../Models/SDK/CustomBulkSessionModel.cs.meta | 18 + .../Models/SDK/CustomBulkSessionsModel.cs | 44 + .../SDK/CustomBulkSessionsModel.cs.meta | 18 + .../Models/SDK/CustomSessionDeleteModel.cs | 45 + .../SDK/CustomSessionDeleteModel.cs.meta | 18 + .../Edgegap/Models/SDK/CustomSessionModel.cs | 45 + .../Models/SDK/CustomSessionModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Delete.cs | 54 + .../Hosting/Edgegap/Models/SDK/Delete.cs.meta | 18 + .../Edgegap/Models/SDK/DeployEnvModel.cs | 63 + .../Edgegap/Models/SDK/DeployEnvModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/DeployModel.cs | 180 + .../Edgegap/Models/SDK/DeployModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Deployment.cs | 134 + .../Edgegap/Models/SDK/Deployment.cs.meta | 18 + .../Edgegap/Models/SDK/DeploymentLocation.cs | 99 + .../Models/SDK/DeploymentLocation.cs.meta | 18 + .../Models/SDK/DeploymentSessionContext.cs | 90 + .../SDK/DeploymentSessionContext.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Deployments.cs | 72 + .../Edgegap/Models/SDK/Deployments.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Error.cs | 45 + .../Hosting/Edgegap/Models/SDK/Error.cs.meta | 18 + .../Edgegap/Models/SDK/GeoIpListModel.cs | 63 + .../Edgegap/Models/SDK/GeoIpListModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Location.cs | 108 + .../Edgegap/Models/SDK/Location.cs.meta | 18 + .../Edgegap/Models/SDK/LocationModel.cs | 54 + .../Edgegap/Models/SDK/LocationModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Locations.cs | 53 + .../Edgegap/Models/SDK/Locations.cs.meta | 18 + .../Models/SDK/MatchmakerComponentCreate.cs | 81 + .../SDK/MatchmakerComponentCreate.cs.meta | 18 + .../SDK/MatchmakerComponentEnvListResponse.cs | 54 + ...MatchmakerComponentEnvListResponse.cs.meta | 18 + .../SDK/MatchmakerComponentEnvsCreate.cs | 54 + .../SDK/MatchmakerComponentEnvsCreate.cs.meta | 18 + .../SDK/MatchmakerComponentEnvsResponse.cs | 54 + .../MatchmakerComponentEnvsResponse.cs.meta | 18 + .../SDK/MatchmakerComponentEnvsUpdate.cs | 54 + .../SDK/MatchmakerComponentEnvsUpdate.cs.meta | 18 + .../SDK/MatchmakerComponentListResponse.cs | 54 + .../MatchmakerComponentListResponse.cs.meta | 18 + .../Models/SDK/MatchmakerComponentResponse.cs | 81 + .../SDK/MatchmakerComponentResponse.cs.meta | 18 + .../Models/SDK/MatchmakerComponentUpdate.cs | 81 + .../SDK/MatchmakerComponentUpdate.cs.meta | 18 + .../Edgegap/Models/SDK/MatchmakerCreate.cs | 45 + .../Models/SDK/MatchmakerCreate.cs.meta | 18 + .../Models/SDK/MatchmakerListResponse.cs | 54 + .../Models/SDK/MatchmakerListResponse.cs.meta | 18 + .../SDK/MatchmakerManagedReleaseCreate.cs | 45 + .../MatchmakerManagedReleaseCreate.cs.meta | 18 + .../SDK/MatchmakerManagedReleaseResponse.cs | 45 + .../MatchmakerManagedReleaseResponse.cs.meta | 18 + .../SDK/MatchmakerManagedReleaseUpdate.cs | 45 + .../MatchmakerManagedReleaseUpdate.cs.meta | 18 + .../SDK/MatchmakerReleaseConfigCreate.cs | 54 + .../SDK/MatchmakerReleaseConfigCreate.cs.meta | 18 + .../SDK/MatchmakerReleaseConfigResponse.cs | 54 + .../MatchmakerReleaseConfigResponse.cs.meta | 18 + .../SDK/MatchmakerReleaseConfigUpdate.cs | 54 + .../SDK/MatchmakerReleaseConfigUpdate.cs.meta | 18 + .../Models/SDK/MatchmakerReleaseCreate.cs | 63 + .../SDK/MatchmakerReleaseCreate.cs.meta | 18 + .../Models/SDK/MatchmakerReleaseCreateBase.cs | 45 + .../SDK/MatchmakerReleaseCreateBase.cs.meta | 18 + .../Models/SDK/MatchmakerReleaseResponse.cs | 63 + .../SDK/MatchmakerReleaseResponse.cs.meta | 18 + .../SDK/MatchmakerReleaseResponseBase.cs | 63 + .../SDK/MatchmakerReleaseResponseBase.cs.meta | 18 + .../Models/SDK/MatchmakerReleaseUpdate.cs | 63 + .../SDK/MatchmakerReleaseUpdate.cs.meta | 18 + .../Models/SDK/MatchmakerReleaseUpdateBase.cs | 45 + .../SDK/MatchmakerReleaseUpdateBase.cs.meta | 18 + .../Edgegap/Models/SDK/MatchmakerResponse.cs | 45 + .../Models/SDK/MatchmakerResponse.cs.meta | 18 + .../Edgegap/Models/SDK/MatchmakerUpdate.cs | 45 + .../Models/SDK/MatchmakerUpdate.cs.meta | 18 + .../Edgegap/Models/SDK/MetricsModel.cs | 60 + .../Edgegap/Models/SDK/MetricsModel.cs.meta | 18 + .../Edgegap/Models/SDK/MetricsResponse.cs | 68 + .../Models/SDK/MetricsResponse.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Monitor.cs | 99 + .../Edgegap/Models/SDK/Monitor.cs.meta | 18 + .../Edgegap/Models/SDK/NetworkMetricsModel.cs | 52 + .../Models/SDK/NetworkMetricsModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Pagination.cs | 89 + .../Edgegap/Models/SDK/Pagination.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Paginator.cs | 45 + .../Edgegap/Models/SDK/Paginator.cs.meta | 18 + .../Edgegap/Models/SDK/PatchSessionModel.cs | 45 + .../Models/SDK/PatchSessionModel.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/PortMapping.cs | 99 + .../Edgegap/Models/SDK/PortMapping.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Request.cs | 135 + .../Edgegap/Models/SDK/Request.cs.meta | 18 + .../Edgegap/Models/SDK/SelectorEnvModel.cs | 54 + .../Models/SDK/SelectorEnvModel.cs.meta | 18 + .../Edgegap/Models/SDK/SelectorModel.cs | 63 + .../Edgegap/Models/SDK/SelectorModel.cs.meta | 18 + .../Edgegap/Models/SDK/SessionContext.cs | 108 + .../Edgegap/Models/SDK/SessionContext.cs.meta | 18 + .../Edgegap/Models/SDK/SessionDelete.cs | 63 + .../Edgegap/Models/SDK/SessionDelete.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/SessionGet.cs | 161 + .../Edgegap/Models/SDK/SessionGet.cs.meta | 18 + .../Edgegap/Models/SDK/SessionModel.cs | 144 + .../Edgegap/Models/SDK/SessionModel.cs.meta | 18 + .../Edgegap/Models/SDK/SessionRequest.cs | 90 + .../Edgegap/Models/SDK/SessionRequest.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/SessionUser.cs | 63 + .../Edgegap/Models/SDK/SessionUser.cs.meta | 18 + .../Edgegap/Models/SDK/SessionUserContext.cs | 45 + .../Models/SDK/SessionUserContext.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Sessions.cs | 63 + .../Edgegap/Models/SDK/Sessions.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/StaticSites.cs | 90 + .../Edgegap/Models/SDK/StaticSites.cs.meta | 18 + .../Edgegap/Models/SDK/StaticSitesList.cs | 53 + .../Models/SDK/StaticSitesList.cs.meta | 18 + .../Hosting/Edgegap/Models/SDK/Status.cs | 215 + .../Hosting/Edgegap/Models/SDK/Status.cs.meta | 18 + .../Edgegap/Models/SDK/TotalMetricsModel.cs | 68 + .../Models/SDK/TotalMetricsModel.cs.meta | 18 + .../Edgegap/Newtonsoft_Package_Patch.cs | 103 + .../Edgegap/Newtonsoft_Package_Patch.cs.meta | 18 + Assets/Mirror/Hosting/Edgegap/README.md | 101 + Assets/Mirror/Hosting/Edgegap/README.md.meta | 14 + .../Mirror/Hosting/Edgegap/_MIRROR_README.md | 9 + .../Hosting/Edgegap/_MIRROR_README.md.meta | 14 + Assets/Mirror/Hosting/Edgegap/package.json | 21 + .../Mirror/Hosting/Edgegap/package.json.meta | 14 + Assets/Mirror/Hosting/Readme.txt | 5 + Assets/Mirror/Hosting/Readme.txt.meta | 10 + Assets/Mirror/LICENSE | 22 + Assets/Mirror/LICENSE.meta | 9 + Assets/Mirror/Plugins.meta | 8 + Assets/Mirror/Plugins/Mono.Cecil.meta | 8 + Assets/Mirror/Plugins/Mono.Cecil/License.txt | 25 + .../Plugins/Mono.Cecil/License.txt.meta | 14 + .../Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll | Bin 0 -> 43520 bytes .../Mono.Cecil/Mono.CecilX.Mdb.dll.meta | 99 + .../Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll | Bin 0 -> 87552 bytes .../Mono.Cecil/Mono.CecilX.Pdb.dll.meta | 99 + .../Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll | Bin 0 -> 27648 bytes .../Mono.Cecil/Mono.CecilX.Rocks.dll.meta | 99 + .../Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll | Bin 0 -> 340992 bytes .../Plugins/Mono.Cecil/Mono.CecilX.dll.meta | 101 + Assets/Mirror/Presets.meta | 8 + .../Presets/Network Transform (Reliable).meta | 8 + .../ClientAuth-Balanced.preset | 123 + .../ClientAuth-Balanced.preset.meta | 15 + .../ClientAuth-Casual.preset | 123 + .../ClientAuth-Casual.preset.meta | 15 + .../ClientAuth-Responsive.preset | 123 + .../ClientAuth-Responsive.preset.meta | 15 + .../ServerAuth-Balanced.preset | 123 + .../ServerAuth-Balanced.preset.meta | 15 + .../Network Transform (Unreliable).meta | 8 + .../ClientAuth-Balanced.preset | 123 + .../ClientAuth-Balanced.preset.meta | 15 + .../ClientAuth-Casual.preset | 123 + .../ClientAuth-Casual.preset.meta | 15 + .../ClientAuth-Responsive.preset | 123 + .../ClientAuth-Responsive.preset.meta | 15 + .../ServerAuth-Balanced.preset | 123 + .../ServerAuth-Balanced.preset.meta | 15 + Assets/Mirror/Readme.txt | 15 + Assets/Mirror/Readme.txt.meta | 14 + Assets/Mirror/Transports.meta | 8 + Assets/Mirror/Transports/Edgegap.meta | 8 + .../Transports/Edgegap/EdgegapLobby.meta | 8 + .../EdgegapLobby/EdgegapLobbyKcpTransport.cs | 345 + .../EdgegapLobbyKcpTransport.cs.meta | 18 + .../Edgegap/EdgegapLobby/LobbyApi.cs | 295 + .../Edgegap/EdgegapLobby/LobbyApi.cs.meta | 18 + .../LobbyServiceCreateDialogue.cs | 138 + .../LobbyServiceCreateDialogue.cs.meta | 18 + .../EdgegapLobby/LobbyTransportInspector.cs | 64 + .../LobbyTransportInspector.cs.meta | 18 + .../Edgegap/EdgegapLobby/Models.meta | 3 + .../Models/ListLobbiesResponse.cs | 12 + .../Models/ListLobbiesResponse.cs.meta | 18 + .../Edgegap/EdgegapLobby/Models/Lobby.cs | 45 + .../Edgegap/EdgegapLobby/Models/Lobby.cs.meta | 18 + .../Edgegap/EdgegapLobby/Models/LobbyBrief.cs | 17 + .../EdgegapLobby/Models/LobbyBrief.cs.meta | 18 + .../EdgegapLobby/Models/LobbyCreateRequest.cs | 27 + .../Models/LobbyCreateRequest.cs.meta | 18 + .../EdgegapLobby/Models/LobbyIdRequest.cs | 14 + .../Models/LobbyIdRequest.cs.meta | 18 + .../Models/LobbyJoinOrLeaveRequest.cs | 17 + .../Models/LobbyJoinOrLeaveRequest.cs.meta | 18 + .../EdgegapLobby/Models/LobbyUpdateRequest.cs | 12 + .../Models/LobbyUpdateRequest.cs.meta | 18 + .../Transports/Edgegap/EdgegapRelay.meta | 8 + .../Edgegap/EdgegapRelay/EdgegapKcpClient.cs | 141 + .../EdgegapRelay/EdgegapKcpClient.cs.meta | 18 + .../Edgegap/EdgegapRelay/EdgegapKcpServer.cs | 203 + .../EdgegapRelay/EdgegapKcpServer.cs.meta | 18 + .../EdgegapRelay/EdgegapKcpTransport.cs | 162 + .../EdgegapRelay/EdgegapKcpTransport.cs.meta | 18 + .../Edgegap/EdgegapRelay/Protocol.cs | 29 + .../Edgegap/EdgegapRelay/Protocol.cs.meta | 18 + .../Transports/Edgegap/EdgegapRelay/README.md | 20 + .../Edgegap/EdgegapRelay/README.md.meta | 14 + .../EdgegapRelay/RelayCredentialsFromArgs.cs | 25 + .../RelayCredentialsFromArgs.cs.meta | 18 + Assets/Mirror/Transports/Edgegap/edgegap.png | Bin 0 -> 4347 bytes .../Transports/Edgegap/edgegap.png.meta | 130 + Assets/Mirror/Transports/Encryption.meta | 3 + .../Mirror/Transports/Encryption/Editor.meta | 3 + .../Editor/EncryptionTransportEditor.asmdef | 18 + .../EncryptionTransportEditor.asmdef.meta | 14 + .../Editor/EncryptionTransportInspector.cs | 90 + .../EncryptionTransportInspector.cs.meta | 10 + .../Encryption/EncryptedConnection.cs | 554 + .../Encryption/EncryptedConnection.cs.meta | 10 + .../Encryption/EncryptionCredentials.cs | 119 + .../Encryption/EncryptionCredentials.cs.meta | 10 + .../Encryption/EncryptionTransport.cs | 289 + .../Encryption/EncryptionTransport.cs.meta | 18 + .../Mirror/Transports/Encryption/Plugins.meta | 8 + .../Encryption/Plugins/BouncyCastle.meta | 8 + .../Plugins/BouncyCastle/LICENSE.md | 15 + .../Plugins/BouncyCastle/LICENSE.md.meta | 14 + .../Mirror.BouncyCastle.Cryptography.dll | Bin 0 -> 6856192 bytes .../Mirror.BouncyCastle.Cryptography.dll.meta | 40 + .../Transports/Encryption/PubKeyInfo.cs | 12 + .../Transports/Encryption/PubKeyInfo.cs.meta | 10 + .../ThreadedEncryptionKcpTransport.cs | 281 + .../ThreadedEncryptionKcpTransport.cs.meta | 18 + Assets/Mirror/Transports/FizzySteamworks.meta | 8 + .../BidirectionalDictionary.cs | 89 + .../BidirectionalDictionary.cs.meta | 11 + .../FizzySteamworks/FizzySteamworks.asmdef | 22 + .../FizzySteamworks.asmdef.meta | 7 + .../FizzySteamworks/FizzySteamworks.cs | 309 + .../FizzySteamworks/FizzySteamworks.cs.meta | 11 + .../Transports/FizzySteamworks/IClient.cs | 14 + .../FizzySteamworks/IClient.cs.meta | 11 + .../Transports/FizzySteamworks/IServer.cs | 12 + .../FizzySteamworks/IServer.cs.meta | 11 + .../Mirror/Transports/FizzySteamworks/LICENSE | 37 + .../Transports/FizzySteamworks/LICENSE.meta | 7 + .../FizzySteamworks/LegacyClient.cs | 185 + .../FizzySteamworks/LegacyClient.cs.meta | 11 + .../FizzySteamworks/LegacyCommon.cs | 204 + .../FizzySteamworks/LegacyCommon.cs.meta | 11 + .../FizzySteamworks/LegacyServer.cs | 189 + .../FizzySteamworks/LegacyServer.cs.meta | 11 + .../Transports/FizzySteamworks/NextClient.cs | 246 + .../FizzySteamworks/NextClient.cs.meta | 11 + .../Transports/FizzySteamworks/NextCommon.cs | 48 + .../FizzySteamworks/NextCommon.cs.meta | 11 + .../Transports/FizzySteamworks/NextServer.cs | 248 + .../FizzySteamworks/NextServer.cs.meta | 11 + .../Transports/FizzySteamworks/README.md | 55 + .../Transports/FizzySteamworks/README.md.meta | 7 + .../Transports/FizzySteamworks/version.txt | 1 + .../FizzySteamworks/version.txt.meta | 7 + Assets/Mirror/Transports/KCP.meta | 8 + Assets/Mirror/Transports/KCP/KcpTransport.cs | 365 + .../Transports/KCP/KcpTransport.cs.meta | 18 + .../Transports/KCP/ThreadedKcpTransport.cs | 327 + .../KCP/ThreadedKcpTransport.cs.meta | 18 + Assets/Mirror/Transports/KCP/kcp2k.meta | 8 + Assets/Mirror/Transports/KCP/kcp2k/KCP.asmdef | 16 + .../Transports/KCP/kcp2k/KCP.asmdef.meta | 14 + .../Mirror/Transports/KCP/kcp2k/LICENSE.txt | 24 + .../Transports/KCP/kcp2k/LICENSE.txt.meta | 14 + .../Mirror/Transports/KCP/kcp2k/VERSION.txt | 261 + .../Transports/KCP/kcp2k/VERSION.txt.meta | 14 + Assets/Mirror/Transports/KCP/kcp2k/empty.meta | 3 + .../KCP/kcp2k/empty/KcpServerNonAlloc.cs | 1 + .../KCP/kcp2k/empty/KcpServerNonAlloc.cs.meta | 10 + .../Transports/KCP/kcp2k/highlevel.meta | 8 + .../Transports/KCP/kcp2k/highlevel/Common.cs | 75 + .../KCP/kcp2k/highlevel/Common.cs.meta | 10 + .../KCP/kcp2k/highlevel/ErrorCode.cs | 15 + .../KCP/kcp2k/highlevel/ErrorCode.cs.meta | 10 + .../KCP/kcp2k/highlevel/Extensions.cs | 166 + .../KCP/kcp2k/highlevel/Extensions.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpChannel.cs | 10 + .../KCP/kcp2k/highlevel/KcpChannel.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpClient.cs | 292 + .../KCP/kcp2k/highlevel/KcpClient.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpConfig.cs | 97 + .../KCP/kcp2k/highlevel/KcpConfig.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpHeader.cs | 57 + .../KCP/kcp2k/highlevel/KcpHeader.cs.meta | 10 + .../Transports/KCP/kcp2k/highlevel/KcpPeer.cs | 791 + .../KCP/kcp2k/highlevel/KcpPeer.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpServer.cs | 412 + .../KCP/kcp2k/highlevel/KcpServer.cs.meta | 10 + .../kcp2k/highlevel/KcpServerConnection.cs | 126 + .../highlevel/KcpServerConnection.cs.meta | 10 + .../KCP/kcp2k/highlevel/KcpState.cs | 4 + .../KCP/kcp2k/highlevel/KcpState.cs.meta | 18 + .../Transports/KCP/kcp2k/highlevel/Log.cs | 14 + .../KCP/kcp2k/highlevel/Log.cs.meta | 18 + Assets/Mirror/Transports/KCP/kcp2k/kcp.meta | 8 + .../Transports/KCP/kcp2k/kcp/AckItem.cs | 8 + .../Transports/KCP/kcp2k/kcp/AckItem.cs.meta | 18 + .../Transports/KCP/kcp2k/kcp/AssemblyInfo.cs | 3 + .../KCP/kcp2k/kcp/AssemblyInfo.cs.meta | 10 + Assets/Mirror/Transports/KCP/kcp2k/kcp/Kcp.cs | 1118 ++ .../Transports/KCP/kcp2k/kcp/Kcp.cs.meta | 18 + .../Mirror/Transports/KCP/kcp2k/kcp/Pool.cs | 46 + .../Transports/KCP/kcp2k/kcp/Pool.cs.meta | 18 + .../Transports/KCP/kcp2k/kcp/Segment.cs | 78 + .../Transports/KCP/kcp2k/kcp/Segment.cs.meta | 18 + .../Mirror/Transports/KCP/kcp2k/kcp/Utils.cs | 76 + .../Transports/KCP/kcp2k/kcp/Utils.cs.meta | 18 + Assets/Mirror/Transports/Latency.meta | 8 + .../Transports/Latency/LatencySimulation.cs | 319 + .../Latency/LatencySimulation.cs.meta | 18 + Assets/Mirror/Transports/Middleware.meta | 8 + .../Middleware/MiddlewareTransport.cs | 66 + .../Middleware/MiddlewareTransport.cs.meta | 18 + .../Transports/Mirror.Transports.asmdef | 19 + .../Transports/Mirror.Transports.asmdef.meta | 14 + Assets/Mirror/Transports/Multiplex.meta | 8 + .../Multiplex/MultiplexTransport.cs | 458 + .../Multiplex/MultiplexTransport.cs.meta | 18 + Assets/Mirror/Transports/SimpleWeb.meta | 8 + .../Transports/SimpleWeb/.cert.example.Json | 8 + .../SimpleWeb/.cert.example.Json.meta | 9 + .../Mirror/Transports/SimpleWeb/Editor.meta | 8 + .../Editor/ClientWebsocketSettingsDrawer.cs | 71 + .../ClientWebsocketSettingsDrawer.cs.meta | 10 + .../Transports/SimpleWeb/SimpleWeb.meta | 8 + .../SimpleWeb/SimpleWeb/AssemblyInfo.cs | 7 + .../SimpleWeb/SimpleWeb/AssemblyInfo.cs.meta | 18 + .../SimpleWeb/SimpleWeb/CHANGELOG.md | 48 + .../SimpleWeb/SimpleWeb/CHANGELOG.md.meta | 14 + .../SimpleWeb/SimpleWeb/Client.meta | 8 + .../Client/ClientWebsocketSettings.cs | 17 + .../Client/ClientWebsocketSettings.cs.meta | 10 + .../SimpleWeb/Client/SimpleWebClient.cs | 103 + .../SimpleWeb/Client/SimpleWebClient.cs.meta | 18 + .../SimpleWeb/Client/StandAlone.meta | 8 + .../Client/StandAlone/ClientHandshake.cs | 88 + .../Client/StandAlone/ClientHandshake.cs.meta | 18 + .../Client/StandAlone/ClientSslHelper.cs | 47 + .../Client/StandAlone/ClientSslHelper.cs.meta | 18 + .../StandAlone/WebSocketClientStandAlone.cs | 140 + .../WebSocketClientStandAlone.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Client/Webgl.meta | 8 + .../SimpleWeb/Client/Webgl/SimpleWebJSLib.cs | 34 + .../Client/Webgl/SimpleWebJSLib.cs.meta | 18 + .../Client/Webgl/WebSocketClientWebGl.cs | 142 + .../Client/Webgl/WebSocketClientWebGl.cs.meta | 18 + .../SimpleWeb/Client/Webgl/plugin.meta | 8 + .../Client/Webgl/plugin/SimpleWeb.jslib | 123 + .../Client/Webgl/plugin/SimpleWeb.jslib.meta | 44 + .../SimpleWeb/SimpleWeb/Common.meta | 8 + .../SimpleWeb/SimpleWeb/Common/BufferPool.cs | 249 + .../SimpleWeb/Common/BufferPool.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Connection.cs | 134 + .../SimpleWeb/Common/Connection.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Constants.cs | 76 + .../SimpleWeb/Common/Constants.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/EventType.cs | 10 + .../SimpleWeb/Common/EventType.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Log.cs | 270 + .../SimpleWeb/SimpleWeb/Common/Log.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Message.cs | 49 + .../SimpleWeb/Common/Message.cs.meta | 18 + .../SimpleWeb/Common/MessageProcessor.cs | 175 + .../SimpleWeb/Common/MessageProcessor.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/ReadHelper.cs | 123 + .../SimpleWeb/Common/ReadHelper.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/ReceiveLoop.cs | 250 + .../SimpleWeb/Common/ReceiveLoop.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Request.cs | 26 + .../SimpleWeb/Common/Request.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/SendLoop.cs | 222 + .../SimpleWeb/Common/SendLoop.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/TcpConfig.cs | 26 + .../SimpleWeb/Common/TcpConfig.cs.meta | 18 + .../SimpleWeb/SimpleWeb/Common/Utils.cs | 13 + .../SimpleWeb/SimpleWeb/Common/Utils.cs.meta | 18 + .../Transports/SimpleWeb/SimpleWeb/LICENSE | 21 + .../SimpleWeb/SimpleWeb/LICENSE.meta | 14 + .../Transports/SimpleWeb/SimpleWeb/README.txt | 19 + .../SimpleWeb/SimpleWeb/README.txt.meta | 14 + .../SimpleWeb/SimpleWeb/Server.meta | 8 + .../SimpleWeb/Server/ServerHandshake.cs | 156 + .../SimpleWeb/Server/ServerHandshake.cs.meta | 18 + .../SimpleWeb/Server/ServerSslHelper.cs | 74 + .../SimpleWeb/Server/ServerSslHelper.cs.meta | 18 + .../SimpleWeb/Server/SimpleWebServer.cs | 115 + .../SimpleWeb/Server/SimpleWebServer.cs.meta | 18 + .../SimpleWeb/Server/WebSocketServer.cs | 230 + .../SimpleWeb/Server/WebSocketServer.cs.meta | 18 + .../SimpleWeb/SimpleWebTransport.asmdef | 14 + .../SimpleWeb/SimpleWebTransport.asmdef.meta | 14 + .../SimpleWeb/SimpleWeb/SslConfigLoader.cs | 49 + .../SimpleWeb/SslConfigLoader.cs.meta | 18 + .../SimpleWeb/SimpleWebTransport.cs | 389 + .../SimpleWeb/SimpleWebTransport.cs.meta | 18 + Assets/Mirror/Transports/Telepathy.meta | 8 + .../Transports/Telepathy/Telepathy.meta | 8 + .../Transports/Telepathy/Telepathy/Client.cs | 361 + .../Telepathy/Telepathy/Client.cs.meta | 18 + .../Transports/Telepathy/Telepathy/Common.cs | 39 + .../Telepathy/Telepathy/Common.cs.meta | 18 + .../Telepathy/Telepathy/ConnectionState.cs | 35 + .../Telepathy/ConnectionState.cs.meta | 18 + .../Telepathy/Telepathy/EventType.cs | 9 + .../Telepathy/Telepathy/EventType.cs.meta | 18 + .../Transports/Telepathy/Telepathy/LICENSE | 21 + .../Telepathy/Telepathy/LICENSE.meta | 14 + .../Transports/Telepathy/Telepathy/Log.cs | 15 + .../Telepathy/Telepathy/Log.cs.meta | 18 + .../Telepathy/MagnificentReceivePipe.cs | 222 + .../Telepathy/MagnificentReceivePipe.cs.meta | 18 + .../Telepathy/MagnificentSendPipe.cs | 165 + .../Telepathy/MagnificentSendPipe.cs.meta | 18 + .../Telepathy/NetworkStreamExtensions.cs | 67 + .../Telepathy/NetworkStreamExtensions.cs.meta | 18 + .../Transports/Telepathy/Telepathy/Pool.cs | 34 + .../Telepathy/Telepathy/Pool.cs.meta | 18 + .../Transports/Telepathy/Telepathy/Server.cs | 424 + .../Telepathy/Telepathy/Server.cs.meta | 18 + .../Telepathy/Telepathy/Telepathy.asmdef | 12 + .../Telepathy/Telepathy/Telepathy.asmdef.meta | 14 + .../Telepathy/Telepathy/ThreadFunctions.cs | 244 + .../Telepathy/ThreadFunctions.cs.meta | 18 + .../Transports/Telepathy/Telepathy/Utils.cs | 23 + .../Telepathy/Telepathy/Utils.cs.meta | 18 + .../Transports/Telepathy/Telepathy/VERSION | 65 + .../Telepathy/Telepathy/VERSION.meta | 14 + .../Telepathy/TelepathyTransport.cs | 251 + .../Telepathy/TelepathyTransport.cs.meta | 18 + Assets/Mirror/Transports/Threaded.meta | 8 + .../Transports/Threaded/ThreadedTransport.cs | 756 + .../Threaded/ThreadedTransport.cs.meta | 18 + Assets/Mirror/version.txt | 1 + Assets/Mirror/version.txt.meta | 9 + Assets/Models.meta | 8 + Assets/Models/Cloud1.fbx | Bin 0 -> 15932 bytes Assets/Models/Cloud1.fbx.meta | 104 + Assets/Models/Cloud2.fbx | Bin 0 -> 14988 bytes Assets/Models/Cloud2.fbx.meta | 104 + Assets/Models/FallenBranch.fbx | Bin 0 -> 17644 bytes Assets/Models/FallenBranch.fbx.meta | 104 + Assets/Models/FireParticle.fbx | Bin 0 -> 11932 bytes Assets/Models/FireParticle.fbx.meta | 104 + Assets/Models/FireWood.fbx | Bin 0 -> 21388 bytes Assets/Models/FireWood.fbx.meta | 104 + Assets/Models/Flower1.fbx | Bin 0 -> 23644 bytes Assets/Models/Flower1.fbx.meta | 105 + Assets/Models/Flower2.fbx | Bin 0 -> 24204 bytes Assets/Models/Flower2.fbx.meta | 105 + Assets/Models/Flower3.fbx | Bin 0 -> 24172 bytes Assets/Models/Flower3.fbx.meta | 105 + Assets/Models/Grass1.fbx | Bin 0 -> 13420 bytes Assets/Models/Grass1.fbx.meta | 104 + Assets/Models/Grass2.fbx | Bin 0 -> 15260 bytes Assets/Models/Grass2.fbx.meta | 104 + Assets/Models/Grass3.fbx | Bin 0 -> 14636 bytes Assets/Models/Grass3.fbx.meta | 104 + Assets/Models/Grass4.fbx | Bin 0 -> 13356 bytes Assets/Models/Grass4.fbx.meta | 104 + Assets/Models/Ivy1.fbx | Bin 0 -> 16172 bytes Assets/Models/Ivy1.fbx.meta | 104 + Assets/Models/Ivy2.fbx | Bin 0 -> 17660 bytes Assets/Models/Ivy2.fbx.meta | 104 + Assets/Models/LightingPlant1.fbx | Bin 0 -> 22828 bytes Assets/Models/LightingPlant1.fbx.meta | 105 + Assets/Models/LightingPlant2.fbx | Bin 0 -> 21196 bytes Assets/Models/LightingPlant2.fbx.meta | 105 + Assets/Models/Log.fbx | Bin 0 -> 18268 bytes Assets/Models/Log.fbx.meta | 105 + Assets/Models/LowpolyTerrain.fbx | Bin 0 -> 62684 bytes Assets/Models/LowpolyTerrain.fbx.meta | 104 + Assets/Models/Mushroom1.fbx | Bin 0 -> 17244 bytes Assets/Models/Mushroom1.fbx.meta | 105 + Assets/Models/Mushroom2.fbx | Bin 0 -> 17340 bytes Assets/Models/Mushroom2.fbx.meta | 105 + Assets/Models/MushroomLarge.fbx | Bin 0 -> 17772 bytes Assets/Models/MushroomLarge.fbx.meta | 105 + Assets/Models/Paddle.fbx | Bin 0 -> 11740 bytes Assets/Models/Paddle.fbx.meta | 104 + Assets/Models/Plant1.fbx | Bin 0 -> 13564 bytes Assets/Models/Plant1.fbx.meta | 104 + Assets/Models/Plant2.fbx | Bin 0 -> 15740 bytes Assets/Models/Plant2.fbx.meta | 104 + Assets/Models/Plant3.fbx | Bin 0 -> 14076 bytes Assets/Models/Plant3.fbx.meta | 104 + Assets/Models/Plant4.fbx | Bin 0 -> 24060 bytes Assets/Models/Plant4.fbx.meta | 105 + Assets/Models/Rock1.fbx | Bin 0 -> 14092 bytes Assets/Models/Rock1.fbx.meta | 105 + Assets/Models/Rock10.fbx | Bin 0 -> 15228 bytes Assets/Models/Rock10.fbx.meta | 104 + Assets/Models/Rock11.fbx | Bin 0 -> 15164 bytes Assets/Models/Rock11.fbx.meta | 104 + Assets/Models/Rock12.fbx | Bin 0 -> 14108 bytes Assets/Models/Rock12.fbx.meta | 104 + Assets/Models/Rock2.fbx | Bin 0 -> 13932 bytes Assets/Models/Rock2.fbx.meta | 104 + Assets/Models/Rock3.fbx | Bin 0 -> 13836 bytes Assets/Models/Rock3.fbx.meta | 104 + Assets/Models/Rock4.fbx | Bin 0 -> 15228 bytes Assets/Models/Rock4.fbx.meta | 104 + Assets/Models/Rock5.fbx | Bin 0 -> 19708 bytes Assets/Models/Rock5.fbx.meta | 104 + Assets/Models/Rock6.fbx | Bin 0 -> 15820 bytes Assets/Models/Rock6.fbx.meta | 104 + Assets/Models/Rock7.fbx | Bin 0 -> 12540 bytes Assets/Models/Rock7.fbx.meta | 104 + Assets/Models/Rock8.fbx | Bin 0 -> 12940 bytes Assets/Models/Rock8.fbx.meta | 104 + Assets/Models/Rock9.fbx | Bin 0 -> 15004 bytes Assets/Models/Rock9.fbx.meta | 104 + Assets/Models/Tent.fbx | Bin 0 -> 18044 bytes Assets/Models/Tent.fbx.meta | 105 + Assets/Models/Tree1.fbx | Bin 0 -> 27132 bytes Assets/Models/Tree1.fbx.meta | 105 + Assets/Models/Tree2.fbx | Bin 0 -> 24012 bytes Assets/Models/Tree2.fbx.meta | 104 + Assets/Models/Tree3.fbx | Bin 0 -> 35580 bytes Assets/Models/Tree3.fbx.meta | 106 + Assets/Models/TreeDead1.fbx | Bin 0 -> 16044 bytes Assets/Models/TreeDead1.fbx.meta | 104 + Assets/Models/TreeDead2.fbx | Bin 0 -> 14332 bytes Assets/Models/TreeDead2.fbx.meta | 104 + Assets/Models/TreeStump1.fbx | Bin 0 -> 17852 bytes Assets/Models/TreeStump1.fbx.meta | 105 + Assets/Models/WoodBoat.fbx | Bin 0 -> 12300 bytes Assets/Models/WoodBoat.fbx.meta | 104 + Assets/Models/WoodFence1.fbx | Bin 0 -> 13708 bytes Assets/Models/WoodFence1.fbx.meta | 104 + Assets/Models/WoodFence2.fbx | Bin 0 -> 13900 bytes Assets/Models/WoodFence2.fbx.meta | 104 + Assets/Prefabs.meta | 8 + Assets/Prefabs/Player.prefab | 528 + Assets/Prefabs/Player.prefab.meta | 7 + Assets/Readme.asset | 34 + Assets/Readme.asset.meta | 8 + Assets/Scenes.meta | 8 + Assets/Scenes/Game.unity | 1865 +++ Assets/Scenes/Game.unity.meta | 7 + Assets/Scenes/GameOnline.unity | 1803 +++ Assets/Scenes/GameOnline.unity.meta | 7 + Assets/Scenes/MainMenu.unity | 3657 +++++ Assets/Scenes/MainMenu.unity.meta | 7 + Assets/ScriptTemplates.meta | 8 + ...__Network Manager-NewNetworkManager.cs.txt | 261 + ...work Manager-NewNetworkManager.cs.txt.meta | 14 + ...ctions-NewNetworkManagerWithActions.cs.txt | 365 + ...s-NewNetworkManagerWithActions.cs.txt.meta | 14 + ...thenticator-NewNetworkAuthenticator.cs.txt | 106 + ...icator-NewNetworkAuthenticator.cs.txt.meta | 14 + ...twork Behaviour-NewNetworkBehaviour.cs.txt | 86 + ... Behaviour-NewNetworkBehaviour.cs.txt.meta | 14 + ...ions-NewNetworkBehaviourWithActions.cs.txt | 136 + ...NewNetworkBehaviourWithActions.cs.txt.meta | 14 + ...Management-CustomInterestManagement.cs.txt | 94 + ...ement-CustomInterestManagement.cs.txt.meta | 14 + ... Room Manager-NewNetworkRoomManager.cs.txt | 184 + ... Manager-NewNetworkRoomManager.cs.txt.meta | 14 + ...rk Room Player-NewNetworkRoomPlayer.cs.txt | 107 + ...om Player-NewNetworkRoomPlayer.cs.txt.meta | 14 + ...twork Discovery-NewNetworkDiscovery.cs.txt | 99 + ... Discovery-NewNetworkDiscovery.cs.txt.meta | 14 + ...twork Transform-NewNetworkTransform.cs.txt | 149 + ... Transform-NewNetworkTransform.cs.txt.meta | 14 + Assets/ScriptTemplates/Editor.meta | 8 + .../Editor/MoveToAssetsFolder.cs | 42 + .../Editor/MoveToAssetsFolder.cs.meta | 18 + Assets/Scripts.meta | 5 + Assets/Scripts/LobbyHandle.cs | 71 + Assets/Scripts/LobbyHandle.cs.meta | 2 + Assets/Scripts/MenuFunctions.cs | 88 + Assets/Scripts/MenuFunctions.cs.meta | 2 + Assets/Scripts/Movement.cs | 161 + Assets/Scripts/Movement.cs.meta | 2 + Assets/Scripts/PlayerCameraController.cs | 102 + Assets/Scripts/PlayerCameraController.cs.meta | 2 + Assets/Scripts/Steamworks.NET.meta | 5 + Assets/Scripts/Steamworks.NET/SteamManager.cs | 182 + .../Steamworks.NET/SteamManager.cs.meta | 8 + Assets/Settings.meta | 8 + Assets/Settings/DefaultVolumeProfile.asset | 982 ++ .../Settings/DefaultVolumeProfile.asset.meta | 8 + Assets/Settings/Mobile_RPAsset.asset | 135 + Assets/Settings/Mobile_RPAsset.asset.meta | 8 + Assets/Settings/Mobile_Renderer.asset | 52 + Assets/Settings/Mobile_Renderer.asset.meta | 8 + Assets/Settings/PC_RPAsset.asset | 136 + Assets/Settings/PC_RPAsset.asset.meta | 8 + Assets/Settings/PC_Renderer.asset | 95 + Assets/Settings/PC_Renderer.asset.meta | 8 + Assets/Settings/SampleSceneProfile.asset | 159 + Assets/Settings/SampleSceneProfile.asset.meta | 8 + ...niversalRenderPipelineGlobalSettings.asset | 274 + ...salRenderPipelineGlobalSettings.asset.meta | 8 + Assets/TextMesh Pro.meta | 8 + Assets/TextMesh Pro/Examples & Extras.meta | 8 + .../TextMesh Pro/Examples & Extras/Fonts.meta | 8 + .../Examples & Extras/Fonts/Anton OFL.txt | 93 + .../Fonts/Anton OFL.txt.meta | 8 + .../Examples & Extras/Fonts/Anton.ttf | Bin 0 -> 42376 bytes .../Examples & Extras/Fonts/Anton.ttf.meta | 19 + .../Examples & Extras/Fonts/Bangers - OFL.txt | 93 + .../Fonts/Bangers - OFL.txt.meta | 8 + .../Examples & Extras/Fonts/Bangers.ttf | Bin 0 -> 39676 bytes .../Examples & Extras/Fonts/Bangers.ttf.meta | 19 + .../Fonts/Electronic Highway Sign.TTF | Bin 0 -> 73060 bytes .../Fonts/Electronic Highway Sign.TTF.meta | 22 + .../Fonts/Oswald-Bold - OFL.txt | 92 + .../Fonts/Oswald-Bold - OFL.txt.meta | 8 + .../Examples & Extras/Fonts/Oswald-Bold.ttf | Bin 0 -> 53056 bytes .../Fonts/Oswald-Bold.ttf.meta | 19 + .../Fonts/Roboto-Bold - AFL.txt | 202 + .../Fonts/Roboto-Bold - AFL.txt.meta | 8 + .../Fonts/Roboto-Bold - License.txt | 3 + .../Fonts/Roboto-Bold - License.txt.meta | 8 + .../Examples & Extras/Fonts/Roboto-Bold.ttf | Bin 0 -> 170760 bytes .../Fonts/Roboto-Bold.ttf.meta | 22 + .../Examples & Extras/Fonts/Unity - OFL.txt | 92 + .../Fonts/Unity - OFL.txt.meta | 8 + .../Examples & Extras/Fonts/Unity.ttf | Bin 0 -> 1644 bytes .../Examples & Extras/Fonts/Unity.ttf.meta | 21 + .../Examples & Extras/Materials.meta | 9 + .../Crate - Surface Shader Scene.mat | 84 + .../Crate - Surface Shader Scene.mat.meta | 6 + .../Materials/Crate - URP.mat | 138 + .../Materials/Crate - URP.mat.meta | 8 + .../Materials/Ground - Logo Scene.mat | 207 + .../Materials/Ground - Logo Scene.mat.meta | 6 + .../Ground - Surface Shader Scene.mat | 112 + .../Ground - Surface Shader Scene.mat.meta | 6 + .../Materials/Ground - URP.mat | 173 + .../Materials/Ground - URP.mat.meta | 8 + .../Materials/Small Crate_diffuse.mat | 127 + .../Materials/Small Crate_diffuse.mat.meta | 8 + .../Examples & Extras/Prefabs.meta | 9 + .../Prefabs/Text Popup.prefab | 280 + .../Prefabs/Text Popup.prefab.meta | 8 + .../Prefabs/TextMeshPro - Prefab 1.prefab | 219 + .../TextMeshPro - Prefab 1.prefab.meta | 6 + .../Prefabs/TextMeshPro - Prefab 2.prefab | 219 + .../TextMeshPro - Prefab 2.prefab.meta | 6 + .../Examples & Extras/Resources.meta | 9 + .../Resources/Color Gradient Presets.meta | 8 + .../Blue to Purple - Vertical.asset | 17 + .../Blue to Purple - Vertical.asset.meta | 8 + .../Dark to Light Green - Vertical.asset | 17 + .../Dark to Light Green - Vertical.asset.meta | 8 + .../Light to Dark Green - Vertical.asset | 17 + .../Light to Dark Green - Vertical.asset.meta | 8 + .../Yellow to Orange - Vertical.asset | 17 + .../Yellow to Orange - Vertical.asset.meta | 8 + .../Resources/Fonts & Materials.meta | 9 + .../Anton SDF - Drop Shadow.mat | 104 + .../Anton SDF - Drop Shadow.mat.meta | 8 + .../Fonts & Materials/Anton SDF - Outline.mat | 104 + .../Anton SDF - Outline.mat.meta | 8 + .../Anton SDF - Sunny Days.mat | 104 + .../Anton SDF - Sunny Days.mat.meta | 8 + .../Fonts & Materials/Anton SDF.asset | 318 + .../Fonts & Materials/Anton SDF.asset.meta | 8 + .../Bangers SDF - Drop Shadow - 2 Pass.mat | 112 + ...angers SDF - Drop Shadow - 2 Pass.mat.meta | 8 + .../Bangers SDF - Drop Shadow.mat | 110 + .../Bangers SDF - Drop Shadow.mat.meta | 8 + .../Bangers SDF - Outline.mat | 110 + .../Bangers SDF - Outline.mat.meta | 8 + .../Fonts & Materials/Bangers SDF Glow.mat | 113 + .../Bangers SDF Glow.mat.meta | 8 + .../Bangers SDF Logo - URP.mat | 151 + .../Bangers SDF Logo - URP.mat.meta | 8 + .../Fonts & Materials/Bangers SDF Logo.mat | 101 + .../Bangers SDF Logo.mat.meta | 6 + .../Fonts & Materials/Bangers SDF.asset | 302 + .../Fonts & Materials/Bangers SDF.asset.meta | 6 + .../Electronic Highway Sign SDF.asset | 302 + .../Electronic Highway Sign SDF.asset.meta | 8 + .../LiberationSans SDF - Metalic Green.mat | 104 + ...iberationSans SDF - Metalic Green.mat.meta | 8 + .../LiberationSans SDF - Overlay.mat | 62 + .../LiberationSans SDF - Overlay.mat.meta | 8 + .../LiberationSans SDF - Soft Mask.mat | 112 + .../LiberationSans SDF - Soft Mask.mat.meta | 8 + .../Fonts & Materials/Oswald Bold SDF.asset | 302 + .../Oswald Bold SDF.asset.meta | 8 + .../Roboto-Bold SDF - Drop Shadow.mat | 104 + .../Roboto-Bold SDF - Drop Shadow.mat.meta | 8 + .../Roboto-Bold SDF - HDRP Unlit.mat | 191 + .../Roboto-Bold SDF - HDRP Unlit.mat.meta | 8 + .../Roboto-Bold SDF - Surface.mat | 107 + .../Roboto-Bold SDF - Surface.mat.meta | 8 + .../Roboto-Bold SDF - URP.mat | 157 + .../Roboto-Bold SDF - URP.mat.meta | 8 + .../Fonts & Materials/Roboto-Bold SDF.asset | 302 + .../Roboto-Bold SDF.asset.meta | 8 + .../Unity SDF - HDRP LIT - Bloom.mat | 223 + .../Unity SDF - HDRP LIT - Bloom.mat.meta | 8 + .../Unity SDF - HDRP LIT - Outline.mat | 173 + .../Unity SDF - HDRP LIT - Outline.mat.meta | 8 + .../Fonts & Materials/Unity SDF.asset | 389 + .../Fonts & Materials/Unity SDF.asset.meta | 8 + .../Resources/Sprite Assets.meta | 9 + .../Sprite Assets/Default Sprite Asset.asset | 351 + .../Default Sprite Asset.asset.meta | 8 + .../Sprite Assets/DropCap Numbers.asset | 406 + .../Sprite Assets/DropCap Numbers.asset.meta | 8 + .../Examples & Extras/Scenes.meta | 9 + .../01- Single Line TextMesh Pro.unity | 380 + .../01- Single Line TextMesh Pro.unity.meta | 24 + .../Scenes/02 - Multi-line TextMesh Pro.unity | 384 + .../02 - Multi-line TextMesh Pro.unity.meta | 24 + .../Scenes/03 - Line Justification.unity | 896 ++ .../Scenes/03 - Line Justification.unity.meta | 24 + .../Scenes/04 - Word Wrapping.unity | 379 + .../Scenes/04 - Word Wrapping.unity.meta | 24 + .../Scenes/05 - Style Tags.unity | 1017 ++ .../Scenes/05 - Style Tags.unity.meta | 24 + .../06 - Extra Rich Text Examples.unity | 677 + .../06 - Extra Rich Text Examples.unity.meta | 6 + ...07 - Superscript & Subscript Example.unity | 383 + ...Superscript & Subscript Example.unity.meta | 24 + .../Scenes/08 - Improved Text Alignment.unity | 544 + .../08 - Improved Text Alignment.unity.meta | 6 + .../Scenes/09 - Margin Tag Example.unity | 945 ++ .../Scenes/09 - Margin Tag Example.unity.meta | 8 + ...10 - Bullets & Numbered List Example.unity | 665 + ...Bullets & Numbered List Example.unity.meta | 8 + .../Scenes/11 - The Style Tag.unity | 554 + .../Scenes/11 - The Style Tag.unity.meta | 8 + .../Scenes/12 - Link Example.unity | 779 + .../Scenes/12 - Link Example.unity.meta | 8 + .../Scenes/12a - Text Interactions.unity | 807 ++ .../Scenes/12a - Text Interactions.unity.meta | 8 + .../Scenes/13 - Soft Hyphenation.unity | 507 + .../Scenes/13 - Soft Hyphenation.unity.meta | 8 + .../Scenes/14 - Multi Font & Sprites.unity | 544 + .../14 - Multi Font & Sprites.unity.meta | 8 + .../15 - Inline Graphics & Sprites.unity | 595 + .../15 - Inline Graphics & Sprites.unity.meta | 6 + ... - Linked text overflow mode example.unity | 1063 ++ ...nked text overflow mode example.unity.meta | 8 + .../Scenes/17 - Old Computer Terminal.unity | 691 + .../17 - Old Computer Terminal.unity.meta | 8 + .../18 - ScrollRect & Masking & Layout.unity | 9490 ++++++++++++ ...- ScrollRect & Masking & Layout.unity.meta | 8 + .../19 - Masking Texture & Soft Mask.unity | 604 + ...9 - Masking Texture & Soft Mask.unity.meta | 8 + .../20 - Input Field with Scrollbar.unity | 2242 +++ ...20 - Input Field with Scrollbar.unity.meta | 8 + .../Scenes/21 - Script Example.unity | 239 + .../Scenes/21 - Script Example.unity.meta | 24 + .../Scenes/22 - Basic Scripting Example.unity | 447 + .../22 - Basic Scripting Example.unity.meta | 8 + .../23 - Animating Vertex Attributes.unity | 520 + ...3 - Animating Vertex Attributes.unity.meta | 8 + .../24 - Surface Shader Example URP.unity | 3160 ++++ ...24 - Surface Shader Example URP.unity.meta | 24 + .../Scenes/24 - Surface Shader Example.unity | 2687 ++++ .../24 - Surface Shader Example.unity.meta | 24 + .../Scenes/25 - Sunny Days Example.unity | 615 + .../Scenes/25 - Sunny Days Example.unity.meta | 8 + .../26 - Dropdown Placeholder Example.unity | 3418 +++++ ... - Dropdown Placeholder Example.unity.meta | 7 + .../27 - Double Pass Shader Example.unity | 550 + ...27 - Double Pass Shader Example.unity.meta | 7 + .../Scenes/28 - HDRP Shader Example.meta | 8 + .../Scenes/28 - HDRP Shader Example.unity | 2262 +++ .../28 - HDRP Shader Example.unity.meta | 7 + .../Sky and Fog Volume Profile.asset | 60 + .../Sky and Fog Volume Profile.asset.meta | 8 + .../Scenes/Benchmark (Floating Text).unity | 429 + .../Benchmark (Floating Text).unity.meta | 24 + .../Examples & Extras/Scripts.meta | 9 + .../Examples & Extras/Scripts/Benchmark01.cs | 128 + .../Scripts/Benchmark01.cs.meta | 10 + .../Scripts/Benchmark01_UGUI.cs | 135 + .../Scripts/Benchmark01_UGUI.cs.meta | 10 + .../Examples & Extras/Scripts/Benchmark02.cs | 97 + .../Scripts/Benchmark02.cs.meta | 11 + .../Examples & Extras/Scripts/Benchmark03.cs | 92 + .../Scripts/Benchmark03.cs.meta | 11 + .../Examples & Extras/Scripts/Benchmark04.cs | 85 + .../Scripts/Benchmark04.cs.meta | 11 + .../Scripts/CameraController.cs | 292 + .../Scripts/CameraController.cs.meta | 10 + .../Scripts/ChatController.cs | 51 + .../Scripts/ChatController.cs.meta | 12 + .../Scripts/DropdownSample.cs | 19 + .../Scripts/DropdownSample.cs.meta | 11 + .../Scripts/EnvMapAnimator.cs | 35 + .../Scripts/EnvMapAnimator.cs.meta | 12 + .../Examples & Extras/Scripts/ObjectSpin.cs | 67 + .../Scripts/ObjectSpin.cs.meta | 10 + .../Scripts/ShaderPropAnimator.cs | 51 + .../Scripts/ShaderPropAnimator.cs.meta | 10 + .../Examples & Extras/Scripts/SimpleScript.cs | 58 + .../Scripts/SimpleScript.cs.meta | 10 + .../Scripts/SkewTextExample.cs | 158 + .../Scripts/SkewTextExample.cs.meta | 12 + .../Scripts/TMP_DigitValidator.cs | 27 + .../Scripts/TMP_DigitValidator.cs.meta | 12 + .../Scripts/TMP_ExampleScript_01.cs | 64 + .../Scripts/TMP_ExampleScript_01.cs.meta | 12 + .../Scripts/TMP_FrameRateCounter.cs | 134 + .../Scripts/TMP_FrameRateCounter.cs.meta | 10 + .../Scripts/TMP_PhoneNumberValidator.cs | 105 + .../Scripts/TMP_PhoneNumberValidator.cs.meta | 12 + .../Scripts/TMP_TextEventCheck.cs | 73 + .../Scripts/TMP_TextEventCheck.cs.meta | 12 + .../Scripts/TMP_TextEventHandler.cs | 263 + .../Scripts/TMP_TextEventHandler.cs.meta | 12 + .../Scripts/TMP_TextInfoDebugTool.cs | 652 + .../Scripts/TMP_TextInfoDebugTool.cs.meta | 12 + .../Scripts/TMP_TextSelector_A.cs | 157 + .../Scripts/TMP_TextSelector_A.cs.meta | 12 + .../Scripts/TMP_TextSelector_B.cs | 547 + .../Scripts/TMP_TextSelector_B.cs.meta | 14 + .../Scripts/TMP_UiFrameRateCounter.cs | 125 + .../Scripts/TMP_UiFrameRateCounter.cs.meta | 12 + .../Scripts/TMPro_InstructionOverlay.cs | 84 + .../Scripts/TMPro_InstructionOverlay.cs.meta | 10 + .../Examples & Extras/Scripts/TeleType.cs | 83 + .../Scripts/TeleType.cs.meta | 10 + .../Scripts/TextConsoleSimulator.cs | 121 + .../Scripts/TextConsoleSimulator.cs.meta | 12 + .../Scripts/TextMeshProFloatingText.cs | 223 + .../Scripts/TextMeshProFloatingText.cs.meta | 11 + .../Scripts/TextMeshSpawner.cs | 79 + .../Scripts/TextMeshSpawner.cs.meta | 11 + .../Scripts/VertexColorCycler.cs | 84 + .../Scripts/VertexColorCycler.cs.meta | 12 + .../Examples & Extras/Scripts/VertexJitter.cs | 175 + .../Scripts/VertexJitter.cs.meta | 12 + .../Examples & Extras/Scripts/VertexShakeA.cs | 161 + .../Scripts/VertexShakeA.cs.meta | 12 + .../Examples & Extras/Scripts/VertexShakeB.cs | 185 + .../Scripts/VertexShakeB.cs.meta | 12 + .../Examples & Extras/Scripts/VertexZoom.cs | 192 + .../Scripts/VertexZoom.cs.meta | 12 + .../Scripts/WarpTextExample.cs | 144 + .../Scripts/WarpTextExample.cs.meta | 12 + .../Examples & Extras/Sprites.meta | 9 + .../Sprites/Default Sprites.png | Bin 0 -> 178491 bytes .../Sprites/Default Sprites.png.meta | 437 + .../Sprites/DropCap Numbers.psd | Bin 0 -> 482546 bytes .../Sprites/DropCap Numbers.psd.meta | 166 + .../Examples & Extras/Textures.meta | 9 + .../Textures/Brushed Metal 3.jpg | Bin 0 -> 28175 bytes .../Textures/Brushed Metal 3.jpg.meta | 53 + .../Textures/Floor Cement.jpg | Bin 0 -> 71537 bytes .../Textures/Floor Cement.jpg.meta | 53 + .../Textures/Floor Tiles 1 - diffuse.jpg | Bin 0 -> 155648 bytes .../Textures/Floor Tiles 1 - diffuse.jpg.meta | 53 + .../Textures/Fruit Jelly (B&W).jpg | Bin 0 -> 150089 bytes .../Textures/Fruit Jelly (B&W).jpg.meta | 53 + .../Textures/Gradient Diagonal (Color).jpg | Bin 0 -> 11688 bytes .../Gradient Diagonal (Color).jpg.meta | 57 + .../Textures/Gradient Horizontal (Color).jpg | Bin 0 -> 11341 bytes .../Gradient Horizontal (Color).jpg.meta | 53 + .../Textures/Gradient Vertical (Color).jpg | Bin 0 -> 11336 bytes .../Gradient Vertical (Color).jpg.meta | 53 + .../Textures/Mask Zig-n-Zag.psd | Bin 0 -> 38488 bytes .../Textures/Mask Zig-n-Zag.psd.meta | 56 + .../Textures/Small Crate_diffuse.jpg | Bin 0 -> 95326 bytes .../Textures/Small Crate_diffuse.jpg.meta | 132 + .../Textures/Small Crate_normal.jpg | Bin 0 -> 126976 bytes .../Textures/Small Crate_normal.jpg.meta | 132 + .../Textures/Sunny Days - Seamless.jpg | Bin 0 -> 273488 bytes .../Textures/Sunny Days - Seamless.jpg.meta | 132 + .../Text Overflow - Linked Text Image 1.png | Bin 0 -> 26169 bytes ...xt Overflow - Linked Text Image 1.png.meta | 59 + ...t Overflow - Linked Text UI Screenshot.png | Bin 0 -> 49290 bytes ...rflow - Linked Text UI Screenshot.png.meta | 59 + .../Textures/Wipe Pattern - Circle.psd | Bin 0 -> 32696 bytes .../Textures/Wipe Pattern - Circle.psd.meta | 59 + .../Textures/Wipe Pattern - Diagonal.psd | Bin 0 -> 33064 bytes .../Textures/Wipe Pattern - Diagonal.psd.meta | 58 + .../Textures/Wipe Pattern - Radial Double.psd | Bin 0 -> 33155 bytes .../Wipe Pattern - Radial Double.psd.meta | 58 + .../Textures/Wipe Pattern - Radial Quad.psd | Bin 0 -> 34433 bytes .../Wipe Pattern - Radial Quad.psd.meta | 59 + Assets/TextMesh Pro/Fonts.meta | 8 + .../Fonts/LiberationSans - OFL.txt | 46 + .../Fonts/LiberationSans - OFL.txt.meta | 8 + Assets/TextMesh Pro/Fonts/LiberationSans.ttf | Bin 0 -> 350200 bytes .../Fonts/LiberationSans.ttf.meta | 19 + Assets/TextMesh Pro/Resources.meta | 8 + .../Resources/Fonts & Materials.meta | 9 + .../LiberationSans SDF - Drop Shadow.mat | 106 + .../LiberationSans SDF - Drop Shadow.mat.meta | 8 + .../LiberationSans SDF - Fallback.asset | 348 + .../LiberationSans SDF - Fallback.asset.meta | 8 + .../LiberationSans SDF - Outline.mat | 104 + .../LiberationSans SDF - Outline.mat.meta | 8 + .../LiberationSans SDF.asset | 7821 ++++++++++ .../LiberationSans SDF.asset.meta | 8 + .../LineBreaking Following Characters.txt | 1 + ...LineBreaking Following Characters.txt.meta | 8 + .../LineBreaking Leading Characters.txt | 1 + .../LineBreaking Leading Characters.txt.meta | 8 + .../TextMesh Pro/Resources/Sprite Assets.meta | 9 + .../Resources/Sprite Assets/EmojiOne.asset | 659 + .../Sprite Assets/EmojiOne.asset.meta | 8 + .../TextMesh Pro/Resources/Style Sheets.meta | 9 + .../Style Sheets/Default Style Sheet.asset | 81 + .../Default Style Sheet.asset.meta | 8 + .../TextMesh Pro/Resources/TMP Settings.asset | 52 + .../Resources/TMP Settings.asset.meta | 8 + Assets/TextMesh Pro/Shaders.meta | 8 + Assets/TextMesh Pro/Shaders/SDFFunctions.hlsl | 178 + .../Shaders/SDFFunctions.hlsl.meta | 10 + .../Shaders/TMP_Bitmap-Custom-Atlas.shader | 145 + .../TMP_Bitmap-Custom-Atlas.shader.meta | 9 + .../Shaders/TMP_Bitmap-Mobile.shader | 155 + .../Shaders/TMP_Bitmap-Mobile.shader.meta | 9 + Assets/TextMesh Pro/Shaders/TMP_Bitmap.shader | 145 + .../Shaders/TMP_Bitmap.shader.meta | 9 + .../Shaders/TMP_SDF Overlay.shader | 326 + .../Shaders/TMP_SDF Overlay.shader.meta | 9 + .../TextMesh Pro/Shaders/TMP_SDF SSD.shader | 321 + .../Shaders/TMP_SDF SSD.shader.meta | 9 + .../Shaders/TMP_SDF-HDRP LIT.shadergraph | 12074 ++++++++++++++++ .../Shaders/TMP_SDF-HDRP LIT.shadergraph.meta | 10 + .../Shaders/TMP_SDF-HDRP UNLIT.shadergraph | 11759 +++++++++++++++ .../TMP_SDF-HDRP UNLIT.shadergraph.meta | 10 + .../Shaders/TMP_SDF-Mobile Masking.shader | 258 + .../TMP_SDF-Mobile Masking.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile Overlay.shader | 252 + .../TMP_SDF-Mobile Overlay.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile SSD.shader | 106 + .../Shaders/TMP_SDF-Mobile SSD.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile-2-Pass.shader | 389 + .../Shaders/TMP_SDF-Mobile-2-Pass.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile.shader | 250 + .../Shaders/TMP_SDF-Mobile.shader.meta | 9 + .../Shaders/TMP_SDF-Surface-Mobile.shader | 139 + .../TMP_SDF-Surface-Mobile.shader.meta | 9 + .../Shaders/TMP_SDF-Surface.shader | 159 + .../Shaders/TMP_SDF-Surface.shader.meta | 9 + .../Shaders/TMP_SDF-URP Lit.shadergraph | 11932 +++++++++++++++ .../Shaders/TMP_SDF-URP Lit.shadergraph.meta | 10 + .../Shaders/TMP_SDF-URP Unlit.shadergraph | 11629 +++++++++++++++ .../TMP_SDF-URP Unlit.shadergraph.meta | 10 + Assets/TextMesh Pro/Shaders/TMP_SDF.shader | 326 + .../TextMesh Pro/Shaders/TMP_SDF.shader.meta | 9 + Assets/TextMesh Pro/Shaders/TMP_Sprite.shader | 131 + .../Shaders/TMP_Sprite.shader.meta | 9 + Assets/TextMesh Pro/Shaders/TMPro.cginc | 84 + Assets/TextMesh Pro/Shaders/TMPro.cginc.meta | 9 + .../TextMesh Pro/Shaders/TMPro_Mobile.cginc | 165 + .../Shaders/TMPro_Mobile.cginc.meta | 9 + .../Shaders/TMPro_Properties.cginc | 80 + .../Shaders/TMPro_Properties.cginc.meta | 9 + .../TextMesh Pro/Shaders/TMPro_Surface.cginc | 99 + .../Shaders/TMPro_Surface.cginc.meta | 9 + Assets/TextMesh Pro/Sprites.meta | 8 + .../Sprites/EmojiOne Attribution.txt | 3 + .../Sprites/EmojiOne Attribution.txt.meta | 7 + Assets/TextMesh Pro/Sprites/EmojiOne.json | 156 + .../TextMesh Pro/Sprites/EmojiOne.json.meta | 8 + Assets/TextMesh Pro/Sprites/EmojiOne.png | Bin 0 -> 112319 bytes Assets/TextMesh Pro/Sprites/EmojiOne.png.meta | 431 + Assets/com.rlabrecque.steamworks.net.meta | 8 + .../com.rlabrecque.steamworks.net/Editor.meta | 8 + .../Editor/RedistCopy.cs | 76 + .../Editor/RedistCopy.cs.meta | 11 + .../Editor/RedistInstall.cs | 70 + .../Editor/RedistInstall.cs.meta | 11 + ...om.rlabrecque.steamworks.net.editor.asmdef | 18 + ...abrecque.steamworks.net.editor.asmdef.meta | 7 + .../com.rlabrecque.steamworks.net/LICENSE.md | 21 + .../LICENSE.md.meta | 7 + .../Plugins.meta | 8 + .../Plugins/libsteam_api.so | Bin 0 -> 384800 bytes .../Plugins/libsteam_api.so.meta | 64 + .../Plugins/steam_api.bundle.meta | 65 + .../Plugins/steam_api.bundle/Contents.meta | 8 + .../steam_api.bundle/Contents/Info.plist | 38 + .../steam_api.bundle/Contents/MacOS.meta | 8 + .../Contents/MacOS/libsteam_api.dylib | Bin 0 -> 610384 bytes .../Plugins/steam_api.dll | Bin 0 -> 265064 bytes .../Plugins/steam_api.dll.meta | 64 + .../Plugins/steam_api64.dll | Bin 0 -> 300392 bytes .../Plugins/steam_api64.dll.meta | 64 + .../com.rlabrecque.steamworks.net/README.md | 15 + .../README.md.meta | 7 + .../Runtime.meta | 8 + .../Runtime/CallbackDispatcher.cs | 400 + .../Runtime/CallbackDispatcher.cs.meta | 11 + .../Runtime/CallbackIdentity.cs | 35 + .../Runtime/CallbackIdentity.cs.meta | 11 + .../Runtime/ISteamMatchmakingResponses.cs | 490 + .../ISteamMatchmakingResponses.cs.meta | 11 + .../Runtime/InteropHelp.cs | 267 + .../Runtime/InteropHelp.cs.meta | 11 + .../Runtime/Packsize.cs | 71 + .../Runtime/Packsize.cs.meta | 11 + .../Runtime/Steam.cs | 670 + .../Runtime/Steam.cs.meta | 11 + .../Runtime/Version.cs | 24 + .../Runtime/Version.cs.meta | 11 + .../Runtime/autogen.meta | 8 + .../Runtime/autogen/NativeMethods.cs | 3364 +++++ .../Runtime/autogen/NativeMethods.cs.meta | 11 + .../Runtime/autogen/SteamCallbacks.cs | 2919 ++++ .../Runtime/autogen/SteamCallbacks.cs.meta | 11 + .../Runtime/autogen/SteamConstants.cs | 338 + .../Runtime/autogen/SteamConstants.cs.meta | 11 + .../Runtime/autogen/SteamEnums.cs | 2927 ++++ .../Runtime/autogen/SteamEnums.cs.meta | 11 + .../Runtime/autogen/SteamStructs.cs | 402 + .../Runtime/autogen/SteamStructs.cs.meta | 11 + .../Runtime/autogen/isteamapps.cs | 311 + .../Runtime/autogen/isteamapps.cs.meta | 11 + .../Runtime/autogen/isteamclient.cs | 366 + .../Runtime/autogen/isteamclient.cs.meta | 11 + .../Runtime/autogen/isteamfriends.cs | 688 + .../Runtime/autogen/isteamfriends.cs.meta | 11 + .../Runtime/autogen/isteamgameserver.cs | 450 + .../Runtime/autogen/isteamgameserver.cs.meta | 11 + .../Runtime/autogen/isteamgameserverclient.cs | 366 + .../autogen/isteamgameserverclient.cs.meta | 11 + .../Runtime/autogen/isteamgameserverhttp.cs | 277 + .../autogen/isteamgameserverhttp.cs.meta | 11 + .../autogen/isteamgameserverinventory.cs | 478 + .../autogen/isteamgameserverinventory.cs.meta | 11 + .../autogen/isteamgameservernetworking.cs | 270 + .../isteamgameservernetworking.cs.meta | 11 + .../isteamgameservernetworkingmessages.cs | 142 + ...isteamgameservernetworkingmessages.cs.meta | 11 + .../isteamgameservernetworkingsockets.cs | 1115 ++ .../isteamgameservernetworkingsockets.cs.meta | 11 + .../isteamgameservernetworkingutils.cs | 443 + .../isteamgameservernetworkingutils.cs.meta | 11 + .../Runtime/autogen/isteamgameserverstats.cs | 110 + .../autogen/isteamgameserverstats.cs.meta | 11 + .../Runtime/autogen/isteamgameserverugc.cs | 759 + .../autogen/isteamgameserverugc.cs.meta | 11 + .../Runtime/autogen/isteamgameserverutils.cs | 364 + .../autogen/isteamgameserverutils.cs.meta | 11 + .../Runtime/autogen/isteamhtmlsurface.cs | 341 + .../Runtime/autogen/isteamhtmlsurface.cs.meta | 11 + .../Runtime/autogen/isteamhttp.cs | 277 + .../Runtime/autogen/isteamhttp.cs.meta | 11 + .../Runtime/autogen/isteaminput.cs | 476 + .../Runtime/autogen/isteaminput.cs.meta | 11 + .../Runtime/autogen/isteaminventory.cs | 478 + .../Runtime/autogen/isteaminventory.cs.meta | 11 + .../Runtime/autogen/isteammatchmaking.cs | 892 ++ .../Runtime/autogen/isteammatchmaking.cs.meta | 11 + .../Runtime/autogen/isteammusic.cs | 69 + .../Runtime/autogen/isteammusic.cs.meta | 11 + .../Runtime/autogen/isteammusicremote.cs | 212 + .../Runtime/autogen/isteammusicremote.cs.meta | 11 + .../Runtime/autogen/isteamnetworking.cs | 270 + .../Runtime/autogen/isteamnetworking.cs.meta | 11 + .../autogen/isteamnetworkingmessages.cs | 142 + .../autogen/isteamnetworkingmessages.cs.meta | 11 + .../autogen/isteamnetworkingsockets.cs | 1115 ++ .../autogen/isteamnetworkingsockets.cs.meta | 11 + .../Runtime/autogen/isteamnetworkingutils.cs | 443 + .../autogen/isteamnetworkingutils.cs.meta | 11 + .../Runtime/autogen/isteamparentalsettings.cs | 51 + .../autogen/isteamparentalsettings.cs.meta | 11 + .../Runtime/autogen/isteamremoteplay.cs | 90 + .../Runtime/autogen/isteamremoteplay.cs.meta | 11 + .../Runtime/autogen/isteamremotestorage.cs | 434 + .../autogen/isteamremotestorage.cs.meta | 11 + .../Runtime/autogen/isteamscreenshots.cs | 111 + .../Runtime/autogen/isteamscreenshots.cs.meta | 11 + .../Runtime/autogen/isteamtimeline.cs | 88 + .../Runtime/autogen/isteamtimeline.cs.meta | 11 + .../Runtime/autogen/isteamugc.cs | 759 + .../Runtime/autogen/isteamugc.cs.meta | 11 + .../Runtime/autogen/isteamuser.cs | 381 + .../Runtime/autogen/isteamuser.cs.meta | 11 + .../Runtime/autogen/isteamuserstats.cs | 474 + .../Runtime/autogen/isteamuserstats.cs.meta | 11 + .../Runtime/autogen/isteamutils.cs | 364 + .../Runtime/autogen/isteamutils.cs.meta | 11 + .../Runtime/autogen/isteamvideo.cs | 54 + .../Runtime/autogen/isteamvideo.cs.meta | 11 + .../com.rlabrecque.steamworks.net.asmdef | 20 + .../com.rlabrecque.steamworks.net.asmdef.meta | 7 + .../Runtime/types.meta | 8 + .../Runtime/types/MatchmakingTypes.meta | 8 + .../MatchmakingTypes/gameserveritem_t.cs | 106 + .../MatchmakingTypes/gameserveritem_t.cs.meta | 11 + .../types/MatchmakingTypes/servernetadr_t.cs | 116 + .../MatchmakingTypes/servernetadr_t.cs.meta | 11 + .../Runtime/types/SteamClient.meta | 8 + .../SteamAPIWarningMessageHook_t.cs | 22 + .../SteamAPIWarningMessageHook_t.cs.meta | 11 + .../SteamAPI_CheckCallbackRegistered_t.cs | 22 + ...SteamAPI_CheckCallbackRegistered_t.cs.meta | 11 + .../Runtime/types/SteamClientPublic.meta | 8 + .../types/SteamClientPublic/CGameID.cs | 154 + .../types/SteamClientPublic/CGameID.cs.meta | 11 + .../types/SteamClientPublic/CSteamID.cs | 269 + .../types/SteamClientPublic/CSteamID.cs.meta | 11 + .../types/SteamClientPublic/HAuthTicket.cs | 65 + .../SteamClientPublic/HAuthTicket.cs.meta | 11 + .../Runtime/types/SteamDatagramTickets.meta | 8 + .../SteamDatagramHostedAddress.cs | 44 + .../SteamDatagramHostedAddress.cs.meta | 11 + .../SteamDatagramRelayAuthTicket.cs | 144 + .../SteamDatagramRelayAuthTicket.cs.meta | 11 + .../Runtime/types/SteamFriends.meta | 8 + .../types/SteamFriends/FriendsGroupID_t.cs | 65 + .../SteamFriends/FriendsGroupID_t.cs.meta | 11 + .../Runtime/types/SteamHTMLSurface.meta | 8 + .../types/SteamHTMLSurface/HHTMLBrowser.cs | 65 + .../SteamHTMLSurface/HHTMLBrowser.cs.meta | 11 + .../Runtime/types/SteamHTTP.meta | 8 + .../SteamHTTP/HTTPCookieContainerHandle.cs | 65 + .../HTTPCookieContainerHandle.cs.meta | 11 + .../types/SteamHTTP/HTTPRequestHandle.cs | 65 + .../types/SteamHTTP/HTTPRequestHandle.cs.meta | 11 + .../Runtime/types/SteamInput.meta | 8 + .../SteamInput/InputActionSetHandle_t.cs | 64 + .../SteamInput/InputActionSetHandle_t.cs.meta | 11 + .../SteamInput/InputAnalogActionHandle_t.cs | 64 + .../InputAnalogActionHandle_t.cs.meta | 11 + .../SteamInput/InputDigitalActionHandle_t.cs | 64 + .../InputDigitalActionHandle_t.cs.meta | 11 + .../Runtime/types/SteamInput/InputHandle_t.cs | 64 + .../types/SteamInput/InputHandle_t.cs.meta | 11 + .../SteamInputActionEventCallbackPointer.cs | 22 + ...eamInputActionEventCallbackPointer.cs.meta | 11 + .../SteamInput/SteamInputActionEvent_t.cs | 65 + .../SteamInputActionEvent_t.cs.meta | 11 + .../Runtime/types/SteamInventory.meta | 8 + .../SteamInventory/SteamInventoryResult_t.cs | 65 + .../SteamInventoryResult_t.cs.meta | 11 + .../SteamInventoryUpdateHandle_t.cs | 65 + .../SteamInventoryUpdateHandle_t.cs.meta | 11 + .../types/SteamInventory/SteamItemDef_t.cs | 64 + .../SteamInventory/SteamItemDef_t.cs.meta | 11 + .../SteamInventory/SteamItemInstanceID_t.cs | 65 + .../SteamItemInstanceID_t.cs.meta | 11 + .../Runtime/types/SteamMatchmaking.meta | 8 + .../SteamMatchmaking/HServerListRequest.cs | 61 + .../HServerListRequest.cs.meta | 11 + .../types/SteamMatchmaking/HServerQuery.cs | 65 + .../SteamMatchmaking/HServerQuery.cs.meta | 11 + .../Runtime/types/SteamNetworking.meta | 8 + .../SteamNetworking/SNetListenSocket_t.cs | 64 + .../SNetListenSocket_t.cs.meta | 11 + .../types/SteamNetworking/SNetSocket_t.cs | 64 + .../SteamNetworking/SNetSocket_t.cs.meta | 11 + .../Runtime/types/SteamNetworkingSockets.meta | 8 + .../ISteamNetworkingConnectionSignaling.cs | 65 + ...SteamNetworkingConnectionSignaling.cs.meta | 11 + .../ISteamNetworkingSignalingRecvContext.cs | 65 + ...teamNetworkingSignalingRecvContext.cs.meta | 11 + .../Runtime/types/SteamNetworkingTypes.meta | 8 + .../FSteamNetworkingSocketsDebugOutput.cs | 23 + ...FSteamNetworkingSocketsDebugOutput.cs.meta | 11 + .../HSteamListenSocket.cs | 65 + .../HSteamListenSocket.cs.meta | 11 + .../HSteamNetConnection.cs | 65 + .../HSteamNetConnection.cs.meta | 11 + .../HSteamNetPollGroup.cs | 65 + .../HSteamNetPollGroup.cs.meta | 11 + .../SteamNetworkingConfigValue_t.cs | 64 + .../SteamNetworkingConfigValue_t.cs.meta | 11 + .../SteamNetworkingErrMsg.cs | 30 + .../SteamNetworkingErrMsg.cs.meta | 11 + .../SteamNetworkingIPAddr.cs | 114 + .../SteamNetworkingIPAddr.cs.meta | 11 + .../SteamNetworkingIdentity.cs | 243 + .../SteamNetworkingIdentity.cs.meta | 11 + .../SteamNetworkingMessage_t.cs | 124 + .../SteamNetworkingMessage_t.cs.meta | 11 + .../SteamNetworkingMicroseconds.cs | 64 + .../SteamNetworkingMicroseconds.cs.meta | 11 + .../SteamNetworkingPOPID.cs | 64 + .../SteamNetworkingPOPID.cs.meta | 11 + .../Runtime/types/SteamRemotePlay.meta | 8 + .../SteamRemotePlay/RemotePlaySessionID_t.cs | 64 + .../RemotePlaySessionID_t.cs.meta | 11 + .../Runtime/types/SteamRemoteStorage.meta | 8 + .../SteamRemoteStorage/PublishedFileId_t.cs | 65 + .../PublishedFileId_t.cs.meta | 11 + .../PublishedFileUpdateHandle_t.cs | 65 + .../PublishedFileUpdateHandle_t.cs.meta | 11 + .../UGCFileWriteStreamHandle_t.cs | 65 + .../UGCFileWriteStreamHandle_t.cs.meta | 11 + .../types/SteamRemoteStorage/UGCHandle_t.cs | 65 + .../SteamRemoteStorage/UGCHandle_t.cs.meta | 11 + .../Runtime/types/SteamScreenshots.meta | 8 + .../SteamScreenshots/ScreenshotHandle.cs | 65 + .../SteamScreenshots/ScreenshotHandle.cs.meta | 11 + .../Runtime/types/SteamTypes.meta | 8 + .../Runtime/types/SteamTypes/AccountID_t.cs | 65 + .../types/SteamTypes/AccountID_t.cs.meta | 11 + .../Runtime/types/SteamTypes/AppId_t.cs | 65 + .../Runtime/types/SteamTypes/AppId_t.cs.meta | 11 + .../Runtime/types/SteamTypes/DepotId_t.cs | 65 + .../types/SteamTypes/DepotId_t.cs.meta | 11 + .../types/SteamTypes/PartyBeaconID_t.cs | 65 + .../types/SteamTypes/PartyBeaconID_t.cs.meta | 11 + .../Runtime/types/SteamTypes/RTime32.cs | 64 + .../Runtime/types/SteamTypes/RTime32.cs.meta | 11 + .../types/SteamTypes/SteamAPICall_t.cs | 65 + .../types/SteamTypes/SteamAPICall_t.cs.meta | 11 + .../types/SteamTypes/SteamIPAddress_t.cs | 97 + .../types/SteamTypes/SteamIPAddress_t.cs.meta | 11 + .../Runtime/types/SteamUGC.meta | 8 + .../types/SteamUGC/UGCQueryHandle_t.cs | 65 + .../types/SteamUGC/UGCQueryHandle_t.cs.meta | 11 + .../types/SteamUGC/UGCUpdateHandle_t.cs | 65 + .../types/SteamUGC/UGCUpdateHandle_t.cs.meta | 11 + .../Runtime/types/SteamUserStats.meta | 8 + .../SteamLeaderboardEntries_t.cs | 64 + .../SteamLeaderboardEntries_t.cs.meta | 11 + .../SteamUserStats/SteamLeaderboard_t.cs | 64 + .../SteamUserStats/SteamLeaderboard_t.cs.meta | 11 + .../Runtime/types/Steam_api_common.meta | 8 + .../types/Steam_api_common/HSteamPipe.cs | 64 + .../types/Steam_api_common/HSteamPipe.cs.meta | 11 + .../types/Steam_api_common/HSteamUser.cs | 64 + .../types/Steam_api_common/HSteamUser.cs.meta | 11 + .../package.json | 21 + .../package.json.meta | 7 + Assets/images.meta | 8 + Assets/images/IMG_0149.jpg | Bin 0 -> 2477934 bytes Assets/images/IMG_0149.jpg.meta | 156 + Assets/images/hyprland.png | Bin 0 -> 562985 bytes Assets/images/hyprland.png.meta | 156 + Packages/manifest.json | 50 + Packages/packages-lock.json | 508 + ProjectSettings/AudioManager.asset | 19 + ProjectSettings/ClusterInputManager.asset | 6 + ProjectSettings/DynamicsManager.asset | 36 + ProjectSettings/EditorBuildSettings.asset | 19 + ProjectSettings/EditorSettings.asset | 48 + ProjectSettings/GraphicsSettings.asset | 67 + ProjectSettings/InputManager.asset | 487 + ProjectSettings/MemorySettings.asset | 35 + ProjectSettings/MultiplayerManager.asset | 7 + ProjectSettings/NavMeshAreas.asset | 91 + ProjectSettings/PackageManagerSettings.asset | 43 + ProjectSettings/Physics2DSettings.asset | 56 + ProjectSettings/PresetManager.asset | 7 + ProjectSettings/ProjectSettings.asset | 932 ++ ProjectSettings/ProjectVersion.txt | 2 + ProjectSettings/QualitySettings.asset | 134 + ProjectSettings/SceneTemplateSettings.json | 121 + ProjectSettings/ShaderGraphSettings.asset | 18 + ProjectSettings/TagManager.asset | 52 + ProjectSettings/TimeManager.asset | 9 + ProjectSettings/URPProjectSettings.asset | 15 + ProjectSettings/UnityConnectSettings.asset | 36 + ProjectSettings/VFXManager.asset | 12 + ProjectSettings/VersionControlSettings.asset | 8 + ProjectSettings/XRSettings.asset | 10 + ignore.conf | 61 + steam_appid.txt | 1 + 3174 files changed, 428263 insertions(+) create mode 100644 .gitignore create mode 100644 .plastic/plastic.changes create mode 100644 .plastic/plastic.selector create mode 100644 .plastic/plastic.wktree create mode 100644 .plastic/plastic.workspace create mode 100644 Assets/InputSystem_Actions.inputactions create mode 100644 Assets/InputSystem_Actions.inputactions.meta create mode 100644 Assets/Materials.meta create mode 100644 Assets/Materials/CloudMat.mat create mode 100644 Assets/Materials/CloudMat.mat.meta create mode 100644 Assets/Materials/DemoPlaneMat.mat create mode 100644 Assets/Materials/DemoPlaneMat.mat.meta create mode 100644 Assets/Materials/EmissionBlueMat.mat create mode 100644 Assets/Materials/EmissionBlueMat.mat.meta create mode 100644 Assets/Materials/EmissionYellowMat.mat create mode 100644 Assets/Materials/EmissionYellowMat.mat.meta create mode 100644 Assets/Materials/Flower1.mat create mode 100644 Assets/Materials/Flower1.mat.meta create mode 100644 Assets/Materials/Flower2Mat.mat create mode 100644 Assets/Materials/Flower2Mat.mat.meta create mode 100644 Assets/Materials/Flower3Mat.mat create mode 100644 Assets/Materials/Flower3Mat.mat.meta create mode 100644 Assets/Materials/Flower4Mat.mat create mode 100644 Assets/Materials/Flower4Mat.mat.meta create mode 100644 Assets/Materials/Mushroom1Mat.mat create mode 100644 Assets/Materials/Mushroom1Mat.mat.meta create mode 100644 Assets/Materials/Mushroom2Mat.mat create mode 100644 Assets/Materials/Mushroom2Mat.mat.meta create mode 100644 Assets/Materials/Mushroom3Mat.mat create mode 100644 Assets/Materials/Mushroom3Mat.mat.meta create mode 100644 Assets/Materials/PlantMat.mat create mode 100644 Assets/Materials/PlantMat.mat.meta create mode 100644 Assets/Materials/RockMat.mat create mode 100644 Assets/Materials/RockMat.mat.meta create mode 100644 Assets/Materials/TreeGreen1Mat.mat create mode 100644 Assets/Materials/TreeGreen1Mat.mat.meta create mode 100644 Assets/Materials/TreeGreen2Mat.mat create mode 100644 Assets/Materials/TreeGreen2Mat.mat.meta create mode 100644 Assets/Materials/TreeOrangeMat.mat create mode 100644 Assets/Materials/TreeOrangeMat.mat.meta create mode 100644 Assets/Materials/TreePinkMat.mat create mode 100644 Assets/Materials/TreePinkMat.mat.meta create mode 100644 Assets/Materials/TreeRedMat.mat create mode 100644 Assets/Materials/TreeRedMat.mat.meta create mode 100644 Assets/Materials/TreeYellowMat.mat create mode 100644 Assets/Materials/TreeYellowMat.mat.meta create mode 100644 Assets/Materials/Wood1Mat.mat create mode 100644 Assets/Materials/Wood1Mat.mat.meta create mode 100644 Assets/Materials/Wood2Mat.mat create mode 100644 Assets/Materials/Wood2Mat.mat.meta create mode 100644 Assets/Mirror.meta create mode 100644 Assets/Mirror/Authenticators.meta create mode 100644 Assets/Mirror/Authenticators/BasicAuthenticator.cs create mode 100644 Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta create mode 100644 Assets/Mirror/Authenticators/DeviceAuthenticator.cs create mode 100644 Assets/Mirror/Authenticators/DeviceAuthenticator.cs.meta create mode 100644 Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef create mode 100644 Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta create mode 100644 Assets/Mirror/Authenticators/TimeoutAuthenticator.cs create mode 100644 Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta create mode 100644 Assets/Mirror/CompilerSymbols.meta create mode 100644 Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef create mode 100644 Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta create mode 100644 Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs create mode 100644 Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta create mode 100644 Assets/Mirror/Components.meta create mode 100644 Assets/Mirror/Components/AssemblyInfo.cs create mode 100644 Assets/Mirror/Components/AssemblyInfo.cs.meta create mode 100644 Assets/Mirror/Components/Discovery.meta create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscovery.cs create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs create mode 100644 Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta create mode 100644 Assets/Mirror/Components/Discovery/ServerRequest.cs create mode 100644 Assets/Mirror/Components/Discovery/ServerRequest.cs.meta create mode 100644 Assets/Mirror/Components/Discovery/ServerResponse.cs create mode 100644 Assets/Mirror/Components/Discovery/ServerResponse.cs.meta create mode 100644 Assets/Mirror/Components/GUIConsole.cs create mode 100644 Assets/Mirror/Components/GUIConsole.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Distance.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Match.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Scene.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SceneDistance.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Team.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs.meta create mode 100644 Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs create mode 100644 Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs.meta create mode 100644 Assets/Mirror/Components/LagCompensation.meta create mode 100644 Assets/Mirror/Components/LagCompensation/HistoryCollider.cs create mode 100644 Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta create mode 100644 Assets/Mirror/Components/LagCompensation/LagCompensator.cs create mode 100644 Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta create mode 100644 Assets/Mirror/Components/Mirror.Components.asmdef create mode 100644 Assets/Mirror/Components/Mirror.Components.asmdef.meta create mode 100644 Assets/Mirror/Components/NetworkAnimator.cs create mode 100644 Assets/Mirror/Components/NetworkAnimator.cs.meta create mode 100644 Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs create mode 100644 Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta create mode 100644 Assets/Mirror/Components/NetworkLobbyManager.cs create mode 100644 Assets/Mirror/Components/NetworkLobbyManager.cs.meta create mode 100644 Assets/Mirror/Components/NetworkLobbyPlayer.cs create mode 100644 Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta create mode 100644 Assets/Mirror/Components/NetworkPingDisplay.cs create mode 100644 Assets/Mirror/Components/NetworkPingDisplay.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs create mode 100644 Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRoomManager.cs create mode 100644 Assets/Mirror/Components/NetworkRoomManager.cs.meta create mode 100644 Assets/Mirror/Components/NetworkRoomPlayer.cs create mode 100644 Assets/Mirror/Components/NetworkRoomPlayer.cs.meta create mode 100644 Assets/Mirror/Components/NetworkStatistics.cs create mode 100644 Assets/Mirror/Components/NetworkStatistics.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs create mode 100644 Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat create mode 100644 Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs create mode 100644 Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta create mode 100644 Assets/Mirror/Components/Profiling.meta create mode 100644 Assets/Mirror/Components/Profiling/BaseUIGraph.cs create mode 100644 Assets/Mirror/Components/Profiling/BaseUIGraph.cs.meta create mode 100644 Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs create mode 100644 Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs.meta create mode 100644 Assets/Mirror/Components/Profiling/LineGraph.mat create mode 100644 Assets/Mirror/Components/Profiling/LineGraph.mat.meta create mode 100644 Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs create mode 100644 Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs.meta create mode 100644 Assets/Mirror/Components/Profiling/NetworkGraphLines.shader create mode 100644 Assets/Mirror/Components/Profiling/NetworkGraphLines.shader.meta create mode 100644 Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader create mode 100644 Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader.meta create mode 100644 Assets/Mirror/Components/Profiling/NetworkPingGraph.cs create mode 100644 Assets/Mirror/Components/Profiling/NetworkPingGraph.cs.meta create mode 100644 Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs create mode 100644 Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab.meta create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab create mode 100644 Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab.meta create mode 100644 Assets/Mirror/Components/Profiling/StackedGraph.mat create mode 100644 Assets/Mirror/Components/Profiling/StackedGraph.mat.meta create mode 100644 Assets/Mirror/Components/Profiling/ToggleHotkey.cs create mode 100644 Assets/Mirror/Components/Profiling/ToggleHotkey.cs.meta create mode 100644 Assets/Mirror/Components/RemoteStatistics.cs create mode 100644 Assets/Mirror/Components/RemoteStatistics.cs.meta create mode 100644 Assets/Mirror/Core.meta create mode 100644 Assets/Mirror/Core/AssemblyInfo.cs create mode 100644 Assets/Mirror/Core/AssemblyInfo.cs.meta create mode 100644 Assets/Mirror/Core/Attributes.cs create mode 100644 Assets/Mirror/Core/Attributes.cs.meta create mode 100644 Assets/Mirror/Core/Batching.meta create mode 100644 Assets/Mirror/Core/Batching/Batcher.cs create mode 100644 Assets/Mirror/Core/Batching/Batcher.cs.meta create mode 100644 Assets/Mirror/Core/Batching/Unbatcher.cs create mode 100644 Assets/Mirror/Core/Batching/Unbatcher.cs.meta create mode 100644 Assets/Mirror/Core/ConnectionQuality.cs create mode 100644 Assets/Mirror/Core/ConnectionQuality.cs.meta create mode 100644 Assets/Mirror/Core/HostMode.cs create mode 100644 Assets/Mirror/Core/HostMode.cs.meta create mode 100644 Assets/Mirror/Core/InterestManagement.cs create mode 100644 Assets/Mirror/Core/InterestManagement.cs.meta create mode 100644 Assets/Mirror/Core/InterestManagementBase.cs create mode 100644 Assets/Mirror/Core/InterestManagementBase.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation.meta create mode 100644 Assets/Mirror/Core/LagCompensation/Capture.cs create mode 100644 Assets/Mirror/Core/LagCompensation/Capture.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/HistoryBounds.cs create mode 100644 Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensation.cs create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs create mode 100644 Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta create mode 100644 Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs create mode 100644 Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta create mode 100644 Assets/Mirror/Core/LocalConnectionToClient.cs create mode 100644 Assets/Mirror/Core/LocalConnectionToClient.cs.meta create mode 100644 Assets/Mirror/Core/LocalConnectionToServer.cs create mode 100644 Assets/Mirror/Core/LocalConnectionToServer.cs.meta create mode 100644 Assets/Mirror/Core/Messages.cs create mode 100644 Assets/Mirror/Core/Messages.cs.meta create mode 100644 Assets/Mirror/Core/Mirror.asmdef create mode 100644 Assets/Mirror/Core/Mirror.asmdef.meta create mode 100644 Assets/Mirror/Core/NetworkAuthenticator.cs create mode 100644 Assets/Mirror/Core/NetworkAuthenticator.cs.meta create mode 100644 Assets/Mirror/Core/NetworkBehaviour.cs create mode 100644 Assets/Mirror/Core/NetworkBehaviour.cs.meta create mode 100644 Assets/Mirror/Core/NetworkBehaviourHybrid.cs create mode 100644 Assets/Mirror/Core/NetworkBehaviourHybrid.cs.meta create mode 100644 Assets/Mirror/Core/NetworkBehaviourSyncVar.cs create mode 100644 Assets/Mirror/Core/NetworkBehaviourSyncVar.cs.meta create mode 100644 Assets/Mirror/Core/NetworkClient.cs create mode 100644 Assets/Mirror/Core/NetworkClient.cs.meta create mode 100644 Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs create mode 100644 Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs.meta create mode 100644 Assets/Mirror/Core/NetworkConnection.cs create mode 100644 Assets/Mirror/Core/NetworkConnection.cs.meta create mode 100644 Assets/Mirror/Core/NetworkConnectionToClient.cs create mode 100644 Assets/Mirror/Core/NetworkConnectionToClient.cs.meta create mode 100644 Assets/Mirror/Core/NetworkConnectionToServer.cs create mode 100644 Assets/Mirror/Core/NetworkConnectionToServer.cs.meta create mode 100644 Assets/Mirror/Core/NetworkDiagnostics.cs create mode 100644 Assets/Mirror/Core/NetworkDiagnostics.cs.meta create mode 100644 Assets/Mirror/Core/NetworkIdentity.cs create mode 100644 Assets/Mirror/Core/NetworkIdentity.cs.meta create mode 100644 Assets/Mirror/Core/NetworkLoop.cs create mode 100644 Assets/Mirror/Core/NetworkLoop.cs.meta create mode 100644 Assets/Mirror/Core/NetworkManager.cs create mode 100644 Assets/Mirror/Core/NetworkManager.cs.meta create mode 100644 Assets/Mirror/Core/NetworkManagerHUD.cs create mode 100644 Assets/Mirror/Core/NetworkManagerHUD.cs.meta create mode 100644 Assets/Mirror/Core/NetworkMessage.cs create mode 100644 Assets/Mirror/Core/NetworkMessage.cs.meta create mode 100644 Assets/Mirror/Core/NetworkMessages.cs create mode 100644 Assets/Mirror/Core/NetworkMessages.cs.meta create mode 100644 Assets/Mirror/Core/NetworkReader.cs create mode 100644 Assets/Mirror/Core/NetworkReader.cs.meta create mode 100644 Assets/Mirror/Core/NetworkReaderExtensions.cs create mode 100644 Assets/Mirror/Core/NetworkReaderExtensions.cs.meta create mode 100644 Assets/Mirror/Core/NetworkReaderPool.cs create mode 100644 Assets/Mirror/Core/NetworkReaderPool.cs.meta create mode 100644 Assets/Mirror/Core/NetworkReaderPooled.cs create mode 100644 Assets/Mirror/Core/NetworkReaderPooled.cs.meta create mode 100644 Assets/Mirror/Core/NetworkServer.cs create mode 100644 Assets/Mirror/Core/NetworkServer.cs.meta create mode 100644 Assets/Mirror/Core/NetworkStartPosition.cs create mode 100644 Assets/Mirror/Core/NetworkStartPosition.cs.meta create mode 100644 Assets/Mirror/Core/NetworkTime.cs create mode 100644 Assets/Mirror/Core/NetworkTime.cs.meta create mode 100644 Assets/Mirror/Core/NetworkWriter.cs create mode 100644 Assets/Mirror/Core/NetworkWriter.cs.meta create mode 100644 Assets/Mirror/Core/NetworkWriterExtensions.cs create mode 100644 Assets/Mirror/Core/NetworkWriterExtensions.cs.meta create mode 100644 Assets/Mirror/Core/NetworkWriterPool.cs create mode 100644 Assets/Mirror/Core/NetworkWriterPool.cs.meta create mode 100644 Assets/Mirror/Core/NetworkWriterPooled.cs create mode 100644 Assets/Mirror/Core/NetworkWriterPooled.cs.meta create mode 100644 Assets/Mirror/Core/PortTransport.cs create mode 100644 Assets/Mirror/Core/PortTransport.cs.meta create mode 100644 Assets/Mirror/Core/Prediction.meta create mode 100644 Assets/Mirror/Core/Prediction/Prediction.cs create mode 100644 Assets/Mirror/Core/Prediction/Prediction.cs.meta create mode 100644 Assets/Mirror/Core/RemoteCalls.cs create mode 100644 Assets/Mirror/Core/RemoteCalls.cs.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs create mode 100644 Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta create mode 100644 Assets/Mirror/Core/SyncDictionary.cs create mode 100644 Assets/Mirror/Core/SyncDictionary.cs.meta create mode 100644 Assets/Mirror/Core/SyncList.cs create mode 100644 Assets/Mirror/Core/SyncList.cs.meta create mode 100644 Assets/Mirror/Core/SyncObject.cs create mode 100644 Assets/Mirror/Core/SyncObject.cs.meta create mode 100644 Assets/Mirror/Core/SyncSet.cs create mode 100644 Assets/Mirror/Core/SyncSet.cs.meta create mode 100644 Assets/Mirror/Core/Threading.meta create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ConcurrentPool.cs create mode 100644 Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta create mode 100644 Assets/Mirror/Core/Threading/ThreadLog.cs create mode 100644 Assets/Mirror/Core/Threading/ThreadLog.cs.meta create mode 100644 Assets/Mirror/Core/Threading/WorkerThread.cs create mode 100644 Assets/Mirror/Core/Threading/WorkerThread.cs.meta create mode 100644 Assets/Mirror/Core/Tools.meta create mode 100644 Assets/Mirror/Core/Tools/AccurateInterval.cs create mode 100644 Assets/Mirror/Core/Tools/AccurateInterval.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Compression.cs create mode 100644 Assets/Mirror/Core/Tools/Compression.cs.meta create mode 100644 Assets/Mirror/Core/Tools/DeltaCompression.cs create mode 100644 Assets/Mirror/Core/Tools/DeltaCompression.cs.meta create mode 100644 Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs create mode 100644 Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Extensions.cs create mode 100644 Assets/Mirror/Core/Tools/Extensions.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Half.cs create mode 100644 Assets/Mirror/Core/Tools/Half.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Mathd.cs create mode 100644 Assets/Mirror/Core/Tools/Mathd.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Pool.cs create mode 100644 Assets/Mirror/Core/Tools/Pool.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Readme.txt create mode 100644 Assets/Mirror/Core/Tools/Readme.txt.meta create mode 100644 Assets/Mirror/Core/Tools/TimeSample.cs create mode 100644 Assets/Mirror/Core/Tools/TimeSample.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Utils.cs create mode 100644 Assets/Mirror/Core/Tools/Utils.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Vector3Long.cs create mode 100644 Assets/Mirror/Core/Tools/Vector3Long.cs.meta create mode 100644 Assets/Mirror/Core/Tools/Vector4Long.cs create mode 100644 Assets/Mirror/Core/Tools/Vector4Long.cs.meta create mode 100644 Assets/Mirror/Core/Transport.cs create mode 100644 Assets/Mirror/Core/Transport.cs.meta create mode 100644 Assets/Mirror/Core/TransportError.cs create mode 100644 Assets/Mirror/Core/TransportError.cs.meta create mode 100644 Assets/Mirror/Core/WeaverFuse.cs create mode 100644 Assets/Mirror/Core/WeaverFuse.cs.meta create mode 100644 Assets/Mirror/Editor.meta create mode 100644 Assets/Mirror/Editor/AndroidManifestHelper.cs create mode 100644 Assets/Mirror/Editor/AndroidManifestHelper.cs.meta create mode 100644 Assets/Mirror/Editor/EditorHelper.cs create mode 100644 Assets/Mirror/Editor/EditorHelper.cs.meta create mode 100644 Assets/Mirror/Editor/Icon.meta create mode 100644 Assets/Mirror/Editor/Icon/MirrorIcon.png create mode 100644 Assets/Mirror/Editor/Icon/MirrorIcon.png.meta create mode 100644 Assets/Mirror/Editor/InspectorHelper.cs create mode 100644 Assets/Mirror/Editor/InspectorHelper.cs.meta create mode 100644 Assets/Mirror/Editor/LagCompensatorInspector.cs create mode 100644 Assets/Mirror/Editor/LagCompensatorInspector.cs.meta create mode 100644 Assets/Mirror/Editor/Mirror.Editor.asmdef create mode 100644 Assets/Mirror/Editor/Mirror.Editor.asmdef.meta create mode 100644 Assets/Mirror/Editor/NetworkBehaviourInspector.cs create mode 100644 Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta create mode 100644 Assets/Mirror/Editor/NetworkInformationPreview.cs create mode 100644 Assets/Mirror/Editor/NetworkInformationPreview.cs.meta create mode 100644 Assets/Mirror/Editor/NetworkManagerEditor.cs create mode 100644 Assets/Mirror/Editor/NetworkManagerEditor.cs.meta create mode 100644 Assets/Mirror/Editor/NetworkScenePostProcess.cs create mode 100644 Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta create mode 100644 Assets/Mirror/Editor/ReadOnlyDrawer.cs create mode 100644 Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta create mode 100644 Assets/Mirror/Editor/SceneDrawer.cs create mode 100644 Assets/Mirror/Editor/SceneDrawer.cs.meta create mode 100644 Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs create mode 100644 Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs.meta create mode 100644 Assets/Mirror/Editor/SyncVarAttributeDrawer.cs create mode 100644 Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver.meta create mode 100644 Assets/Mirror/Editor/Weaver/AssemblyInfo.cs create mode 100644 Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs create mode 100644 Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Extensions.cs create mode 100644 Assets/Mirror/Editor/Weaver/Extensions.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Helpers.cs create mode 100644 Assets/Mirror/Editor/Weaver/Helpers.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Logger.cs create mode 100644 Assets/Mirror/Editor/Weaver/Logger.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs create mode 100644 Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Readers.cs create mode 100644 Assets/Mirror/Editor/Weaver/Readers.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Resolvers.cs create mode 100644 Assets/Mirror/Editor/Weaver/Resolvers.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs create mode 100644 Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs create mode 100644 Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef create mode 100644 Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta create mode 100644 Assets/Mirror/Editor/Weaver/Weaver.cs create mode 100644 Assets/Mirror/Editor/Weaver/Weaver.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/WeaverExceptions.cs create mode 100644 Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/WeaverTypes.cs create mode 100644 Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta create mode 100644 Assets/Mirror/Editor/Weaver/Writers.cs create mode 100644 Assets/Mirror/Editor/Weaver/Writers.cs.meta create mode 100644 Assets/Mirror/Editor/Welcome.cs create mode 100644 Assets/Mirror/Editor/Welcome.cs.meta create mode 100644 Assets/Mirror/Examples.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt create mode 100644 Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/LightingData.asset create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Right_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Right_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Up_Tex.jpeg create mode 100644 Assets/Mirror/Examples/AdditiveLevels/Textures/Up_Tex.jpeg.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Capsule.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cube.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Cylinder.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Quad.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Shelter.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Sphere.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Materials/Zone.mat.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Capsule.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cube.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Cylinder.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/PlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/PlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/PlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/PlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Sphere.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Tank.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Prefabs/Zone.prefab.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/README.md create mode 100644 Assets/Mirror/Examples/AdditiveScenes/README.md.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/LightingData.asset create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs create mode 100644 Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity create mode 100644 Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Prefabs.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs.meta create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs create mode 100644 Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs.meta create mode 100644 Assets/Mirror/Examples/Basic.meta create mode 100644 Assets/Mirror/Examples/Basic/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Basic/Prefabs/Player.prefab create mode 100644 Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab create mode 100644 Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta create mode 100644 Assets/Mirror/Examples/Basic/README.md create mode 100644 Assets/Mirror/Examples/Basic/README.md.meta create mode 100644 Assets/Mirror/Examples/Basic/Scenes.meta create mode 100644 Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity create mode 100644 Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity.meta create mode 100644 Assets/Mirror/Examples/Basic/Scripts.meta create mode 100644 Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs create mode 100644 Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta create mode 100644 Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs create mode 100644 Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta create mode 100644 Assets/Mirror/Examples/Basic/Scripts/Player.cs create mode 100644 Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta create mode 100644 Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs create mode 100644 Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta create mode 100644 Assets/Mirror/Examples/Benchmark.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Materials.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Materials/Red.mat create mode 100644 Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Materials/White.mat create mode 100644 Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab create mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab create mode 100644 Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scenes.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity create mode 100644 Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs create mode 100644 Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.cs create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.mat create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.cs create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.mat create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Readme.txt create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/Readme.txt.meta create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt create mode 100644 Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/Readme.md create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/Readme.md.meta create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat create mode 100644 Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader.meta create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt create mode 100644 Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt.meta create mode 100644 Assets/Mirror/Examples/Billiards.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Red.mat create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Red.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Red.prefab create mode 100644 Assets/Mirror/Examples/Billiards/Ball/Red.prefab.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/RedBall.cs create mode 100644 Assets/Mirror/Examples/Billiards/Ball/RedBall.cs.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/White.mat create mode 100644 Assets/Mirror/Examples/Billiards/Ball/White.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/White.prefab create mode 100644 Assets/Mirror/Examples/Billiards/Ball/White.prefab.meta create mode 100644 Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs create mode 100644 Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs.meta create mode 100644 Assets/Mirror/Examples/Billiards/MirrorBilliards.unity create mode 100644 Assets/Mirror/Examples/Billiards/MirrorBilliards.unity.meta create mode 100644 Assets/Mirror/Examples/Billiards/Player.prefab create mode 100644 Assets/Mirror/Examples/Billiards/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab create mode 100644 Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj create mode 100644 Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl create mode 100644 Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Body.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Body.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Edge.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Edge.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Felt.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Felt.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Holes.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Holes.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Lamp.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Lamp.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/License.txt create mode 100644 Assets/Mirror/Examples/Billiards/Table/License.txt.meta create mode 100644 Assets/Mirror/Examples/Billiards/Table/Pockets.mat create mode 100644 Assets/Mirror/Examples/Billiards/Table/Pockets.mat.meta create mode 100644 Assets/Mirror/Examples/Billiards/_Readme.txt create mode 100644 Assets/Mirror/Examples/Billiards/_Readme.txt.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Player.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab.meta create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt create mode 100644 Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt.meta create mode 100644 Assets/Mirror/Examples/CCU.meta create mode 100644 Assets/Mirror/Examples/CCU/CCUNetworkManager.cs create mode 100644 Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/CCU/MirrorCCU.unity create mode 100644 Assets/Mirror/Examples/CCU/MirrorCCU.unity.meta create mode 100644 Assets/Mirror/Examples/CCU/Monster.cs create mode 100644 Assets/Mirror/Examples/CCU/Monster.cs.meta create mode 100644 Assets/Mirror/Examples/CCU/Monster.prefab create mode 100644 Assets/Mirror/Examples/CCU/Monster.prefab.meta create mode 100644 Assets/Mirror/Examples/CCU/Player.cs create mode 100644 Assets/Mirror/Examples/CCU/Player.cs.meta create mode 100644 Assets/Mirror/Examples/CCU/Player.prefab create mode 100644 Assets/Mirror/Examples/CCU/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/CCU/Readme.txt create mode 100644 Assets/Mirror/Examples/CCU/Readme.txt.meta create mode 100644 Assets/Mirror/Examples/CCU/Red.mat create mode 100644 Assets/Mirror/Examples/CCU/Red.mat.meta create mode 100644 Assets/Mirror/Examples/CCU/White.mat create mode 100644 Assets/Mirror/Examples/CCU/White.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat create mode 100644 Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity create mode 100644 Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab create mode 100644 Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs create mode 100644 Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconRandomColour.png create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconRandomColour.png.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconResetColour.png create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconResetColour.png.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconStickPerson.png create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/IconStickPerson.png.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg create mode 100644 Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg.meta create mode 100644 Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt create mode 100644 Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt.meta create mode 100644 Assets/Mirror/Examples/Chat.meta create mode 100644 Assets/Mirror/Examples/Chat/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Chat/Prefabs/Player.prefab create mode 100644 Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/Chat/Scenes.meta create mode 100644 Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity create mode 100644 Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs create mode 100644 Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs create mode 100644 Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta create mode 100644 Assets/Mirror/Examples/Chat/Scripts/Player.cs create mode 100644 Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat create mode 100644 Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity create mode 100644 Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Prefabs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab create mode 100644 Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab create mode 100644 Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs create mode 100644 Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs.meta create mode 100644 Assets/Mirror/Examples/CouchCoop/_ReadMe.txt create mode 100644 Assets/Mirror/Examples/CouchCoop/_ReadMe.txt.meta create mode 100644 Assets/Mirror/Examples/Discovery.meta create mode 100644 Assets/Mirror/Examples/Discovery/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab create mode 100644 Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/Discovery/Scenes.meta create mode 100644 Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity create mode 100644 Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity create mode 100644 Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks/NavMesh.asset create mode 100644 Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks/NavMesh.asset.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Prefabs.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Prefabs/LobbyUI.prefab create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Prefabs/LobbyUI.prefab.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Prefabs/LobbyUIEntry.prefab create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Prefabs/LobbyUIEntry.prefab.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs create mode 100644 Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs.meta create mode 100644 Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt create mode 100644 Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Mateirals.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs create mode 100644 Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs.meta create mode 100644 Assets/Mirror/Examples/LagCompensation.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/Capture2D.cs create mode 100644 Assets/Mirror/Examples/LagCompensation/Capture2D.cs.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/ClientCube.cs create mode 100644 Assets/Mirror/Examples/LagCompensation/ClientCube.cs.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat create mode 100644 Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity create mode 100644 Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/ServerCube.cs create mode 100644 Assets/Mirror/Examples/LagCompensation/ServerCube.cs.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat create mode 100644 Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs create mode 100644 Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_ create mode 100644 Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_.meta create mode 100644 Assets/Mirror/Examples/LagCompensation/_README.txt create mode 100644 Assets/Mirror/Examples/LagCompensation/_README.txt.meta create mode 100644 Assets/Mirror/Examples/Mirror.Examples.asmdef create mode 100644 Assets/Mirror/Examples/Mirror.Examples.asmdef.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/README.md create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs create mode 100644 Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab create mode 100644 Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/README.md create mode 100644 Assets/Mirror/Examples/MultipleMatches/README.md.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchGUI.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchGUI.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchMessages.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchMessages.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchNetworkManager.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/MatchNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/PlayerGUI.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/PlayerGUI.cs.meta create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/RoomGUI.cs create mode 100644 Assets/Mirror/Examples/MultipleMatches/Scripts/RoomGUI.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Ball.mat create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Ball.mat.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Bat.mat create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Bat.mat.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Bouncy.physicMaterial create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Bouncy.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Box.mat create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Materials/Box.mat.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/PickupsDropsChilds.unity create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/PickupsDropsChilds.unity.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Ball.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Ball.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Bat.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Bat.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Box.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Box.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Custom Robot Kyle.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Custom Robot Kyle.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Player.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/SceneObject.prefab create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Prefabs/SceneObject.prefab.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Enumerations.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Enumerations.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBall.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBall.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBat.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBat.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBox.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/EquippedBox.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/IEquipped.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/Interfaces/IEquipped.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/PickupsDropsChilds.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/PickupsDropsChilds.cs.meta create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/SceneObject.cs create mode 100644 Assets/Mirror/Examples/PickupsDropsChilds/Scripts/SceneObject.cs.meta create mode 100644 Assets/Mirror/Examples/PlayerTest.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerHybrid.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerHybrid.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBHybrid.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBHybrid.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBReliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBUnreliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerRBUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestNetMan.cs create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestNetMan.cs.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene.unity create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene.unity.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/LightingData.asset create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/Lightmap-0_comp_dir.png create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/Lightmap-0_comp_dir.png.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/Lightmap-0_comp_light.exr create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/Lightmap-0_comp_light.exr.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/TerrainData2019.asset create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/TerrainData2019.asset.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/TerrainLayer2019.terrainlayer create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerTestScene/TerrainLayer2019.terrainlayer.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/PlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/TankHybrid.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/TankHybrid.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/TankReliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/TankReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/PlayerTest/TankUnreliable.prefab create mode 100644 Assets/Mirror/Examples/PlayerTest/TankUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/Pong.meta create mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials.meta create mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D create mode 100644 Assets/Mirror/Examples/Pong/PhysicsMaterials/BallMaterial.physicsMaterial2D.meta create mode 100644 Assets/Mirror/Examples/Pong/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Ball.prefab create mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Ball.prefab.meta create mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Racket.prefab create mode 100644 Assets/Mirror/Examples/Pong/Prefabs/Racket.prefab.meta create mode 100644 Assets/Mirror/Examples/Pong/Scenes.meta create mode 100644 Assets/Mirror/Examples/Pong/Scenes/MirrorPong.unity create mode 100644 Assets/Mirror/Examples/Pong/Scenes/MirrorPong.unity.meta create mode 100644 Assets/Mirror/Examples/Pong/Scripts.meta create mode 100644 Assets/Mirror/Examples/Pong/Scripts/Ball.cs create mode 100644 Assets/Mirror/Examples/Pong/Scripts/Ball.cs.meta create mode 100644 Assets/Mirror/Examples/Pong/Scripts/NetworkManagerPong.cs create mode 100644 Assets/Mirror/Examples/Pong/Scripts/NetworkManagerPong.cs.meta create mode 100644 Assets/Mirror/Examples/Pong/Scripts/Player.cs create mode 100644 Assets/Mirror/Examples/Pong/Scripts/Player.cs.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites/Ball.png create mode 100644 Assets/Mirror/Examples/Pong/Sprites/Ball.png.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites/DottedLine.png create mode 100644 Assets/Mirror/Examples/Pong/Sprites/DottedLine.png.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites/Racket.png create mode 100644 Assets/Mirror/Examples/Pong/Sprites/Racket.png.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallHorizontal.png create mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallHorizontal.png.meta create mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallVertical.png create mode 100644 Assets/Mirror/Examples/Pong/Sprites/WallVertical.png.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Floor.mat create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Floor.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Server.mat create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Materials/Server.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/PhysicMaterials.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/PhysicMaterials/Ball.physicMaterial create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/PhysicMaterials/Ball.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/PhysicMaterials/Floor.physicMaterial create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/PhysicMaterials/Floor.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Prefabs.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Prefabs/Player Ball.prefab create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Prefabs/Player Ball.prefab.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Prefabs/Server Ball.prefab create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Prefabs/Server Ball.prefab.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scenes.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scenes/MirrorRigidbodyBenchmark.unity create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scenes/MirrorRigidbodyBenchmark.unity.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/AddForce.cs create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/AddForce.cs.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/AutoForce.cs create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/AutoForce.cs.meta create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/RigidbodyBenchmarkNetworkManager.cs create mode 100644 Assets/Mirror/Examples/RigidbodyBenchmark/Scripts/RigidbodyBenchmarkNetworkManager.cs.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Floor.mat create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Floor.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Server.mat create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Materials/Server.mat.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Ball.physicMaterial create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Ball.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Floor.physicMaterial create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/PhysicMaterials/Floor.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs/Player Ball.prefab create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Prefabs/Player Ball.prefab.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes/MirrorBounceScene.unity create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scenes/MirrorBounceScene.unity.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts.meta create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts/AddForce.cs create mode 100644 Assets/Mirror/Examples/RigidbodyPhysics/Scripts/AddForce.cs.meta create mode 100644 Assets/Mirror/Examples/Room.meta create mode 100644 Assets/Mirror/Examples/Room/Materials.meta create mode 100644 Assets/Mirror/Examples/Room/Materials/PlayArea.mat create mode 100644 Assets/Mirror/Examples/Room/Materials/PlayArea.mat.meta create mode 100644 Assets/Mirror/Examples/Room/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/Room/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/Room/Materials/Prize.mat create mode 100644 Assets/Mirror/Examples/Room/Materials/Prize.mat.meta create mode 100644 Assets/Mirror/Examples/Room/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/Room/Prefabs/GamePlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/Room/Prefabs/Reward.prefab create mode 100644 Assets/Mirror/Examples/Room/Prefabs/Reward.prefab.meta create mode 100644 Assets/Mirror/Examples/Room/Prefabs/RoomPlayer.prefab create mode 100644 Assets/Mirror/Examples/Room/Prefabs/RoomPlayer.prefab.meta create mode 100644 Assets/Mirror/Examples/Room/README.md create mode 100644 Assets/Mirror/Examples/Room/README.md.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame.unity create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame.unity.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame/LightingData.asset create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomGame/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomOffline.unity.meta create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomOnline.unity create mode 100644 Assets/Mirror/Examples/Room/Scenes/MirrorRoomOnline.unity.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs create mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomManagerExt.cs.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs create mode 100644 Assets/Mirror/Examples/Room/Scripts/NetworkRoomPlayerExt.cs.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerScore.cs create mode 100644 Assets/Mirror/Examples/Room/Scripts/PlayerScore.cs.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts/Reward.cs create mode 100644 Assets/Mirror/Examples/Room/Scripts/Reward.cs.meta create mode 100644 Assets/Mirror/Examples/Room/Scripts/Spawner.cs create mode 100644 Assets/Mirror/Examples/Room/Scripts/Spawner.cs.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientCube.cs.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientMaterial.mat create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ClientMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/MirrorSnapshotInterpolation.unity create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/MirrorSnapshotInterpolation.unity.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/README.txt create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/README.txt.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerCube.cs.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerMaterial.mat create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/ServerMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/Snapshot3D.cs.meta create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/_DISABLE VSYNC_ create mode 100644 Assets/Mirror/Examples/Snapshot Interpolation/_DISABLE VSYNC_.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/CubeMaterial.mat create mode 100644 Assets/Mirror/Examples/StackedPrediction/CubeMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/CubeMaterial.physicMaterial create mode 100644 Assets/Mirror/Examples/StackedPrediction/CubeMaterial.physicMaterial.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/GroundMaterial.mat create mode 100644 Assets/Mirror/Examples/StackedPrediction/GroundMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/MirrorStackedPrediction.unity create mode 100644 Assets/Mirror/Examples/StackedPrediction/MirrorStackedPrediction.unity.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/NetworkManagerStackedPrediction.cs create mode 100644 Assets/Mirror/Examples/StackedPrediction/NetworkManagerStackedPrediction.cs.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/PlayerForce.cs create mode 100644 Assets/Mirror/Examples/StackedPrediction/PlayerForce.cs.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/PlayerSpectator.prefab create mode 100644 Assets/Mirror/Examples/StackedPrediction/PlayerSpectator.prefab.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/PredictedCube.prefab create mode 100644 Assets/Mirror/Examples/StackedPrediction/PredictedCube.prefab.meta create mode 100644 Assets/Mirror/Examples/StackedPrediction/_Readme.txt create mode 100644 Assets/Mirror/Examples/StackedPrediction/_Readme.txt.meta create mode 100644 Assets/Mirror/Examples/SyncDirection.meta create mode 100644 Assets/Mirror/Examples/SyncDirection/MirrorSyncDirection.unity create mode 100644 Assets/Mirror/Examples/SyncDirection/MirrorSyncDirection.unity.meta create mode 100644 Assets/Mirror/Examples/SyncDirection/Player.cs create mode 100644 Assets/Mirror/Examples/SyncDirection/Player.cs.meta create mode 100644 Assets/Mirror/Examples/SyncDirection/Player.prefab create mode 100644 Assets/Mirror/Examples/SyncDirection/Player.prefab.meta create mode 100644 Assets/Mirror/Examples/SyncDirection/White.mat create mode 100644 Assets/Mirror/Examples/SyncDirection/White.mat.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Materials.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Materials/MaterialPlayer.mat create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Materials/MaterialPlayer.mat.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Materials/MaterialTrigger.mat create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Materials/MaterialTrigger.mat.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/MirrorTankTheftAuto.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/MirrorTankTheftAuto.unity create mode 100644 Assets/Mirror/Examples/TankTheftAuto/MirrorTankTheftAuto.unity.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/MirrorTankTheftAuto/LightingData.asset create mode 100644 Assets/Mirror/Examples/TankTheftAuto/MirrorTankTheftAuto/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/PlayerReliable.prefab create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/PlayerReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/PlayerUnreliable.prefab create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/PlayerUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/TankReliable.prefab create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/TankReliable.prefab.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/TankUnreliable.prefab create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Prefabs/TankUnreliable.prefab.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Scripts.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Scripts/TankAuthority.cs create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Scripts/TankAuthority.cs.meta create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Scripts/TankTheftAutoNetMan.cs create mode 100644 Assets/Mirror/Examples/TankTheftAuto/Scripts/TankTheftAutoNetMan.cs.meta create mode 100644 Assets/Mirror/Examples/Tanks.meta create mode 100644 Assets/Mirror/Examples/Tanks/Prefabs.meta create mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Projectile.prefab create mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Projectile.prefab.meta create mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Tank.prefab create mode 100644 Assets/Mirror/Examples/Tanks/Prefabs/Tank.prefab.meta create mode 100644 Assets/Mirror/Examples/Tanks/Readme.txt create mode 100644 Assets/Mirror/Examples/Tanks/Readme.txt.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scenes.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scenes/MirrorTanks.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scenes/MirrorTanks.unity create mode 100644 Assets/Mirror/Examples/Tanks/Scenes/MirrorTanks.unity.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scenes/MirrorTanks/NavMesh.asset create mode 100644 Assets/Mirror/Examples/Tanks/Scenes/MirrorTanks/NavMesh.asset.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scripts.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Box.cs create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Box.cs.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Projectile.cs create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Projectile.cs.meta create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Tank.cs create mode 100644 Assets/Mirror/Examples/Tanks/Scripts/Tank.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/DeathSplatter.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/DeathSplatter.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Enemy.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Enemy.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/EnemyHand1.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/EnemyHand1.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/EnemyHand2.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/EnemyHand2.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Flash.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Flash.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Floor.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Floor.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/HitPoint.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/HitPoint.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialBlack.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialBlack.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialGrey.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialGrey.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialWalls.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialWalls.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialYellow.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/MaterialYellow.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Player.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/Player.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/PlayerLF.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/PlayerLF.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/PlayerRF.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/PlayerRF.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/RespawnPortal.mat create mode 100644 Assets/Mirror/Examples/TopDownShooter/Materials/RespawnPortal.mat.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/DeathSplatter.prefab create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/DeathSplatter.prefab.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/EnemyPrefab.prefab create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/EnemyPrefab.prefab.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/PlayerPrefab.prefab create mode 100644 Assets/Mirror/Examples/TopDownShooter/Prefabs/PlayerPrefab.prefab.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter.unity create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter.unity.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/LightingData.asset create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/LightingData.asset.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/NavMesh.asset create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/NavMesh.asset.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/ReflectionProbe-0.exr create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scenes/MirrorTopDownShooter/ReflectionProbe-0.exr.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CameraTopDown.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CameraTopDown.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CanvasHUD.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CanvasHUD.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CanvasTopDown.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/CanvasTopDown.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/EnemyTopDown.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/EnemyTopDown.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/NetworkTopDown.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/NetworkTopDown.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/PlayerTopDown.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/PlayerTopDown.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/RespawnPortal.cs create mode 100644 Assets/Mirror/Examples/TopDownShooter/Scripts/RespawnPortal.cs.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/CornerUI.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/CornerUI.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/DeathSplatter.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/DeathSplatter.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Enemy.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Enemy.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/EnemyHand1.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/EnemyHand1.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/EnemyHand2.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/EnemyHand2.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Flash.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Flash.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Floor.jpg create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Floor.jpg.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/HitPoint.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/HitPoint.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Player.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/Player.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/PlayerFootLeft.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/PlayerFootLeft.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/PlayerFootRight.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/PlayerFootRight.png.meta create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/RespawnPortal.png create mode 100644 Assets/Mirror/Examples/TopDownShooter/Textures/RespawnPortal.png.meta create mode 100644 Assets/Mirror/Examples/VR.meta create mode 100644 Assets/Mirror/Examples/VR/Readme.txt create mode 100644 Assets/Mirror/Examples/VR/Readme.txt.meta create mode 100644 Assets/Mirror/Examples/_Common.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/ControllerUIBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/ControllerUIBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerReliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerReliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUI.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUI.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUI.prefab create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUI.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUnreliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/FlyerController/FlyerControllerUnreliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerHybrid.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerHybrid.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerReliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerReliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUI.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUI.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUI.prefab create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUI.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUnreliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerController/PlayerControllerUnreliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBHybrid.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBHybrid.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBReliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBReliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUI.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUI.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUI.prefab create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUI.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUnreliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/PlayerControllerRB/PlayerControllerRBUnreliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerHybrid.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerHybrid.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerReliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerReliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUI.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUI.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUI.prefab create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUI.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUnreliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankControllerUnreliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankHealth.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankHealth.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretBase.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretBase.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretHybrid.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretHybrid.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretReliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretReliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretUnreliable.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TankTurretUnreliable.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TurretUI.cs create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TurretUI.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TurretUI.prefab create mode 100644 Assets/Mirror/Examples/_Common/Controllers/TankController/TurretUI.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts/Fonts.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts/Fonts/Kenney Mini.ttf create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts/Fonts/Kenney Mini.ttf.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts/License.txt create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_kenney-fonts/License.txt.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/Audio.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/Audio/footstep06.ogg create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/Audio/footstep06.ogg.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/Audio/footstep09.ogg create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/Audio/footstep09.ogg.meta create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/License.txt create mode 100644 Assets/Mirror/Examples/_Common/KenneyAssets/kenney_rpg-audio/License.txt.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/License.txt create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/License.txt.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/05._damage_grunt_male.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/05._damage_grunt_male.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/8bit_gunloop_explosion.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/8bit_gunloop_explosion.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/Light Switch Click On Sfx.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/Light Switch Click On Sfx.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/The Good Fight (just intro).mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/The Good Fight (just intro).mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/The Good Fight (no intro).mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/The Good Fight (no intro).mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/hjm-tesla_sound_shot.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/hjm-tesla_sound_shot.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/impactsplat03.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/impactsplat03.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/mutantdie.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/mutantdie.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/vgmenuhighlight.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/vgmenuhighlight.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/wolf_monster.mp3 create mode 100644 Assets/Mirror/Examples/_Common/OpenGameArt/Sounds/wolf_monster.mp3.meta create mode 100644 Assets/Mirror/Examples/_Common/Projectiles.meta create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile.meta create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.cs create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.mat create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.mat.meta create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.prefab create mode 100644 Assets/Mirror/Examples/_Common/Projectiles/TankProjectile/TankProjectile.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Materials.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Materials/Robot_Color.mat create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Materials/Robot_Color.mat.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Models.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Models/Robot Kyle.fbx create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Models/Robot Kyle.fbx.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Robot Kyle.prefab create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Robot Kyle.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Textures.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Textures/Robot_Color.jpeg create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Textures/Robot_Color.jpeg.meta create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Textures/Robot_Normal.jpeg create mode 100644 Assets/Mirror/Examples/_Common/RobotKyle/Textures/Robot_Normal.jpeg.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/CanvasNetworkManagerHUD.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/CanvasNetworkManagerHUD/CanvasNetworkManagerHUD.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/CanvasNetworkManagerHUD/CanvasNetworkManagerHUD.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/CanvasNetworkManagerHUD/CanvasNetworkManagerHUD.prefab create mode 100644 Assets/Mirror/Examples/_Common/Scripts/CanvasNetworkManagerHUD/CanvasNetworkManagerHUD.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/FPS.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/FPS.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/FaceCamera.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/FaceCamera.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PerlinNoise.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PerlinNoise.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PhysicsSimulator.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PhysicsSimulator/PhysicsSimulator.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PhysicsSimulator/PhysicsSimulator.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PhysicsSimulator/PhysicsSimulator.prefab create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PhysicsSimulator/PhysicsSimulator.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PlayerCamera.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/PlayerCamera.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/RandomColor.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/RandomColor.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/Scripts/Respawn.cs create mode 100644 Assets/Mirror/Examples/_Common/Scripts/Respawn.cs.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/BaseColor.png create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/BaseColor.png.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Controller.controller create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Controller.controller.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Emissive.png create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Emissive.png.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Metallic.png create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Metallic.png.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Normal.png create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Normal.png.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Recon_Tank - License.txt create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/Recon_Tank - License.txt.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/TankMaterial.mat create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/TankMaterial.mat.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/reconTank.fbx create mode 100644 Assets/Mirror/Examples/_Common/TankModel/(Public Domain) Recon_Tank/reconTank.fbx.meta create mode 100644 Assets/Mirror/Examples/_Common/TankModel/BasePrefab.prefab create mode 100644 Assets/Mirror/Examples/_Common/TankModel/BasePrefab.prefab.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt Hand Painted Texture - License.txt.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/Dirt.mat.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png create mode 100644 Assets/Mirror/Examples/_Common/Textures/(Public Domain) Dirt Hand Painted Texture/dirt.png.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/Wall01.jpg create mode 100644 Assets/Mirror/Examples/_Common/Textures/Wall01.jpg.meta create mode 100644 Assets/Mirror/Examples/_Common/Textures/Wall01_n.jpg create mode 100644 Assets/Mirror/Examples/_Common/Textures/Wall01_n.jpg.meta create mode 100644 Assets/Mirror/Hosting.meta create mode 100644 Assets/Mirror/Hosting/Edgegap.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/CHANGELOG.md create mode 100644 Assets/Mirror/Hosting/Edgegap/CHANGELOG.md.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Dependencies.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Dependencies/HttpEncoder.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Dependencies/HttpEncoder.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Dependencies/HttpUtility.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Dependencies/HttpUtility.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Edgegap.asmdef create mode 100644 Assets/Mirror/Hosting/Edgegap/Edgegap.asmdef.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapApiBase.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapApiBase.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapAppApi.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapAppApi.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapIpApi.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapIpApi.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapWizardApi.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/EdgegapWizardApi.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/AppPortsData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/AppPortsData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/DeploymentPortsData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/DeploymentPortsData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/LocationData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/LocationData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/ProtocolType.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/ProtocolType.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetAppVersionsResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetAppVersionsResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetAppsResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetAppsResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentsResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetDeploymentsResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/SessionData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/SessionData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/VersionData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Api/Models/VersionData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/ButtonShaker.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/ButtonShaker.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/CustomPopupContent.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/CustomPopupContent.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Dockerfile create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Dockerfile.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapBuildUtils.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapBuildUtils.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapServerData.uss create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapServerData.uss.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapServerDataManager.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapServerDataManager.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindow.uss create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindow.uss.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindow.uxml create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindow.uxml.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindowMetadata.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindowMetadata.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindowV2.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/EdgegapWindowV2.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/BaronNeue SDF.asset create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/BaronNeue SDF.asset.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Spartan-Regular SDF.asset create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Spartan-Regular SDF.asset.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Spartan-SemiBold SDF.asset create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Spartan-SemiBold SDF.asset.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/BaronNeue.otf create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/BaronNeue.otf.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/Spartan.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/Spartan/Spartan-Regular.ttf create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/Spartan/Spartan-Regular.ttf.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/Spartan/Spartan-SemiBold.ttf create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/Spartan/Spartan-SemiBold.ttf.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/UbuntuMono-R SDF.asset create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Fonts/UbuntuMono-R SDF.asset.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/GithubRelease.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/GithubRelease.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/clipboard-128.png create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/clipboard-128.png.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/discord-brands-solid-64px.png create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/discord-brands-solid-64px.png.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/discord-brands-solid.svg create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/discord-brands-solid.svg.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/logo_transparent_400_alpha25.png create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/Images/logo_transparent_400_alpha25.png.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/PackageJSON.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Editor/PackageJSON.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ApiEnvironment.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ApiEnvironment.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ServerStatus.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ServerStatus.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ToolState.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Enums/ToolState.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/LICENSE.md create mode 100644 Assets/Mirror/Hosting/Edgegap/LICENSE.md.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/AppVersionUpdatePatchData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/AppVersionUpdatePatchData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/DeployPostData.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/DeployPostData.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApiModelContainercrashdata.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApiModelContainercrashdata.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApiModelContainerlogs.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApiModelContainerlogs.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppCreation.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppCreation.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersion.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersion.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionCreateSessionConfig.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionCreateSessionConfig.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionEnv.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionEnv.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionPort.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionPort.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionProbe.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionProbe.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionUpdateSessionConfig.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionUpdateSessionConfig.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntry.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntry.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntryPayload.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntryPayload.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntrySuccess.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistEntrySuccess.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersionWhitelistResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersions.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/AppVersions.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Application.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Application.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApplicationPatch.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApplicationPatch.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApplicationPost.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ApplicationPost.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Applications.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Applications.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BaseModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BaseModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BulkSessionDelete.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BulkSessionDelete.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BulkSessionPost.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/BulkSessionPost.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ComponentCredentials.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ComponentCredentials.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ContainerLogStorageModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/ContainerLogStorageModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomBulkSessionModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomBulkSessionModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomBulkSessionsModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomBulkSessionsModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomSessionDeleteModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomSessionDeleteModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomSessionModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/CustomSessionModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Delete.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Delete.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeployEnvModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeployEnvModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeployModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeployModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Deployment.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Deployment.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeploymentLocation.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeploymentLocation.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeploymentSessionContext.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/DeploymentSessionContext.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Deployments.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Deployments.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Error.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Error.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/GeoIpListModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/GeoIpListModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Location.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Location.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/LocationModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/LocationModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Locations.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Locations.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvListResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvListResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentEnvsUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentListResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentListResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerComponentUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerListResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerListResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerManagedReleaseUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseConfigUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseCreate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseCreate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseCreateBase.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseCreateBase.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseResponseBase.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseResponseBase.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseUpdateBase.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerReleaseUpdateBase.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerUpdate.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MatchmakerUpdate.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MetricsModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MetricsModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MetricsResponse.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/MetricsResponse.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Monitor.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Monitor.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/NetworkMetricsModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/NetworkMetricsModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Pagination.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Pagination.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Paginator.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Paginator.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/PatchSessionModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/PatchSessionModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/PortMapping.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/PortMapping.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Request.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Request.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SelectorEnvModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SelectorEnvModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SelectorModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SelectorModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionContext.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionContext.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionDelete.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionDelete.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionGet.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionGet.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionRequest.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionRequest.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionUser.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionUser.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionUserContext.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/SessionUserContext.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Sessions.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Sessions.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/StaticSites.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/StaticSites.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/StaticSitesList.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/StaticSitesList.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Status.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/Status.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/TotalMetricsModel.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Models/SDK/TotalMetricsModel.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/Newtonsoft_Package_Patch.cs create mode 100644 Assets/Mirror/Hosting/Edgegap/Newtonsoft_Package_Patch.cs.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/README.md create mode 100644 Assets/Mirror/Hosting/Edgegap/README.md.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/_MIRROR_README.md create mode 100644 Assets/Mirror/Hosting/Edgegap/_MIRROR_README.md.meta create mode 100644 Assets/Mirror/Hosting/Edgegap/package.json create mode 100644 Assets/Mirror/Hosting/Edgegap/package.json.meta create mode 100644 Assets/Mirror/Hosting/Readme.txt create mode 100644 Assets/Mirror/Hosting/Readme.txt.meta create mode 100644 Assets/Mirror/LICENSE create mode 100644 Assets/Mirror/LICENSE.meta create mode 100644 Assets/Mirror/Plugins.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/License.txt create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/License.txt.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Mdb.dll.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Pdb.dll.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.Rocks.dll.meta create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll create mode 100644 Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll.meta create mode 100644 Assets/Mirror/Presets.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable).meta create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Balanced.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Balanced.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Casual.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Casual.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Responsive.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ClientAuth-Responsive.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ServerAuth-Balanced.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Reliable)/ServerAuth-Balanced.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable).meta create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Balanced.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Balanced.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Casual.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Casual.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Responsive.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ClientAuth-Responsive.preset.meta create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ServerAuth-Balanced.preset create mode 100644 Assets/Mirror/Presets/Network Transform (Unreliable)/ServerAuth-Balanced.preset.meta create mode 100644 Assets/Mirror/Readme.txt create mode 100644 Assets/Mirror/Readme.txt.meta create mode 100644 Assets/Mirror/Transports.meta create mode 100644 Assets/Mirror/Transports/Edgegap.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/EdgegapLobbyKcpTransport.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/EdgegapLobbyKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyApi.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyApi.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyServiceCreateDialogue.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyServiceCreateDialogue.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyTransportInspector.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/LobbyTransportInspector.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/ListLobbiesResponse.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/ListLobbiesResponse.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/Lobby.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/Lobby.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyBrief.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyBrief.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyCreateRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyCreateRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyIdRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyIdRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyJoinOrLeaveRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyJoinOrLeaveRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyUpdateRequest.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapLobby/Models/LobbyUpdateRequest.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpClient.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpClient.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpServer.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpServer.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpTransport.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/EdgegapKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/Protocol.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/Protocol.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/README.md create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/README.md.meta create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/RelayCredentialsFromArgs.cs create mode 100644 Assets/Mirror/Transports/Edgegap/EdgegapRelay/RelayCredentialsFromArgs.cs.meta create mode 100644 Assets/Mirror/Transports/Edgegap/edgegap.png create mode 100644 Assets/Mirror/Transports/Edgegap/edgegap.png.meta create mode 100644 Assets/Mirror/Transports/Encryption.meta create mode 100644 Assets/Mirror/Transports/Encryption/Editor.meta create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportEditor.asmdef create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportEditor.asmdef.meta create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportInspector.cs create mode 100644 Assets/Mirror/Transports/Encryption/Editor/EncryptionTransportInspector.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptedConnection.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptedConnection.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionCredentials.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionCredentials.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionTransport.cs create mode 100644 Assets/Mirror/Transports/Encryption/EncryptionTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/Plugins.meta create mode 100644 Assets/Mirror/Transports/Encryption/Plugins/BouncyCastle.meta create mode 100644 Assets/Mirror/Transports/Encryption/Plugins/BouncyCastle/LICENSE.md create mode 100644 Assets/Mirror/Transports/Encryption/Plugins/BouncyCastle/LICENSE.md.meta create mode 100644 Assets/Mirror/Transports/Encryption/Plugins/BouncyCastle/Mirror.BouncyCastle.Cryptography.dll create mode 100644 Assets/Mirror/Transports/Encryption/Plugins/BouncyCastle/Mirror.BouncyCastle.Cryptography.dll.meta create mode 100644 Assets/Mirror/Transports/Encryption/PubKeyInfo.cs create mode 100644 Assets/Mirror/Transports/Encryption/PubKeyInfo.cs.meta create mode 100644 Assets/Mirror/Transports/Encryption/ThreadedEncryptionKcpTransport.cs create mode 100644 Assets/Mirror/Transports/Encryption/ThreadedEncryptionKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/BidirectionalDictionary.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/BidirectionalDictionary.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/FizzySteamworks.asmdef create mode 100644 Assets/Mirror/Transports/FizzySteamworks/FizzySteamworks.asmdef.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/FizzySteamworks.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/FizzySteamworks.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/IClient.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/IClient.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/IServer.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/IServer.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LICENSE create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LICENSE.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyClient.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyClient.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyCommon.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyCommon.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyServer.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/LegacyServer.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextClient.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextClient.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextCommon.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextCommon.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextServer.cs create mode 100644 Assets/Mirror/Transports/FizzySteamworks/NextServer.cs.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/README.md create mode 100644 Assets/Mirror/Transports/FizzySteamworks/README.md.meta create mode 100644 Assets/Mirror/Transports/FizzySteamworks/version.txt create mode 100644 Assets/Mirror/Transports/FizzySteamworks/version.txt.meta create mode 100644 Assets/Mirror/Transports/KCP.meta create mode 100644 Assets/Mirror/Transports/KCP/KcpTransport.cs create mode 100644 Assets/Mirror/Transports/KCP/KcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/ThreadedKcpTransport.cs create mode 100644 Assets/Mirror/Transports/KCP/ThreadedKcpTransport.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/KCP.asmdef create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/KCP.asmdef.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/LICENSE.txt create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/LICENSE.txt.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/VERSION.txt create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/VERSION.txt.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpServerNonAlloc.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/empty/KcpServerNonAlloc.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Common.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Common.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/ErrorCode.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/ErrorCode.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Extensions.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Extensions.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpChannel.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpChannel.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpClient.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpClient.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpConfig.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpConfig.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpHeader.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpHeader.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpPeer.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpPeer.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpServer.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpServer.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpServerConnection.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpServerConnection.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpState.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/KcpState.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Log.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/highlevel/Log.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/AckItem.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/AckItem.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/AssemblyInfo.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/AssemblyInfo.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Kcp.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Kcp.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Pool.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Pool.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Segment.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Segment.cs.meta create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Utils.cs create mode 100644 Assets/Mirror/Transports/KCP/kcp2k/kcp/Utils.cs.meta create mode 100644 Assets/Mirror/Transports/Latency.meta create mode 100644 Assets/Mirror/Transports/Latency/LatencySimulation.cs create mode 100644 Assets/Mirror/Transports/Latency/LatencySimulation.cs.meta create mode 100644 Assets/Mirror/Transports/Middleware.meta create mode 100644 Assets/Mirror/Transports/Middleware/MiddlewareTransport.cs create mode 100644 Assets/Mirror/Transports/Middleware/MiddlewareTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Mirror.Transports.asmdef create mode 100644 Assets/Mirror/Transports/Mirror.Transports.asmdef.meta create mode 100644 Assets/Mirror/Transports/Multiplex.meta create mode 100644 Assets/Mirror/Transports/Multiplex/MultiplexTransport.cs create mode 100644 Assets/Mirror/Transports/Multiplex/MultiplexTransport.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/.cert.example.Json create mode 100644 Assets/Mirror/Transports/SimpleWeb/.cert.example.Json.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor/ClientWebsocketSettingsDrawer.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/Editor/ClientWebsocketSettingsDrawer.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/AssemblyInfo.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/AssemblyInfo.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/CHANGELOG.md create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/CHANGELOG.md.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/ClientWebsocketSettings.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/ClientWebsocketSettings.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/SimpleWebClient.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/SimpleWebClient.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/ClientHandshake.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/ClientHandshake.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/ClientSslHelper.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/ClientSslHelper.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/WebSocketClientStandAlone.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/StandAlone/WebSocketClientStandAlone.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/SimpleWebJSLib.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/SimpleWebJSLib.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/WebSocketClientWebGl.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/WebSocketClientWebGl.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/plugin.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/plugin/SimpleWeb.jslib create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Client/Webgl/plugin/SimpleWeb.jslib.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/BufferPool.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/BufferPool.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Connection.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Connection.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Constants.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Constants.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/EventType.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/EventType.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Log.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Log.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Message.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Message.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/MessageProcessor.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/MessageProcessor.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/ReadHelper.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/ReadHelper.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/ReceiveLoop.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/ReceiveLoop.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Request.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Request.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/SendLoop.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/SendLoop.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/TcpConfig.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/TcpConfig.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Utils.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Common/Utils.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/LICENSE create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/LICENSE.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/README.txt create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/README.txt.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/ServerHandshake.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/ServerHandshake.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/ServerSslHelper.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/ServerSslHelper.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/SimpleWebServer.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/SimpleWebServer.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/WebSocketServer.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/Server/WebSocketServer.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/SimpleWebTransport.asmdef create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/SimpleWebTransport.asmdef.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/SslConfigLoader.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWeb/SslConfigLoader.cs.meta create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWebTransport.cs create mode 100644 Assets/Mirror/Transports/SimpleWeb/SimpleWebTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Client.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Client.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Common.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Common.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/ConnectionState.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/ConnectionState.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/EventType.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/EventType.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/LICENSE create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/LICENSE.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Log.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Log.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/MagnificentReceivePipe.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/MagnificentReceivePipe.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/MagnificentSendPipe.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/MagnificentSendPipe.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/NetworkStreamExtensions.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/NetworkStreamExtensions.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Pool.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Pool.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Server.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Server.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Telepathy.asmdef create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Telepathy.asmdef.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/ThreadFunctions.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/ThreadFunctions.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Utils.cs create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/Utils.cs.meta create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/VERSION create mode 100644 Assets/Mirror/Transports/Telepathy/Telepathy/VERSION.meta create mode 100644 Assets/Mirror/Transports/Telepathy/TelepathyTransport.cs create mode 100644 Assets/Mirror/Transports/Telepathy/TelepathyTransport.cs.meta create mode 100644 Assets/Mirror/Transports/Threaded.meta create mode 100644 Assets/Mirror/Transports/Threaded/ThreadedTransport.cs create mode 100644 Assets/Mirror/Transports/Threaded/ThreadedTransport.cs.meta create mode 100644 Assets/Mirror/version.txt create mode 100644 Assets/Mirror/version.txt.meta create mode 100644 Assets/Models.meta create mode 100644 Assets/Models/Cloud1.fbx create mode 100644 Assets/Models/Cloud1.fbx.meta create mode 100644 Assets/Models/Cloud2.fbx create mode 100644 Assets/Models/Cloud2.fbx.meta create mode 100644 Assets/Models/FallenBranch.fbx create mode 100644 Assets/Models/FallenBranch.fbx.meta create mode 100644 Assets/Models/FireParticle.fbx create mode 100644 Assets/Models/FireParticle.fbx.meta create mode 100644 Assets/Models/FireWood.fbx create mode 100644 Assets/Models/FireWood.fbx.meta create mode 100644 Assets/Models/Flower1.fbx create mode 100644 Assets/Models/Flower1.fbx.meta create mode 100644 Assets/Models/Flower2.fbx create mode 100644 Assets/Models/Flower2.fbx.meta create mode 100644 Assets/Models/Flower3.fbx create mode 100644 Assets/Models/Flower3.fbx.meta create mode 100644 Assets/Models/Grass1.fbx create mode 100644 Assets/Models/Grass1.fbx.meta create mode 100644 Assets/Models/Grass2.fbx create mode 100644 Assets/Models/Grass2.fbx.meta create mode 100644 Assets/Models/Grass3.fbx create mode 100644 Assets/Models/Grass3.fbx.meta create mode 100644 Assets/Models/Grass4.fbx create mode 100644 Assets/Models/Grass4.fbx.meta create mode 100644 Assets/Models/Ivy1.fbx create mode 100644 Assets/Models/Ivy1.fbx.meta create mode 100644 Assets/Models/Ivy2.fbx create mode 100644 Assets/Models/Ivy2.fbx.meta create mode 100644 Assets/Models/LightingPlant1.fbx create mode 100644 Assets/Models/LightingPlant1.fbx.meta create mode 100644 Assets/Models/LightingPlant2.fbx create mode 100644 Assets/Models/LightingPlant2.fbx.meta create mode 100644 Assets/Models/Log.fbx create mode 100644 Assets/Models/Log.fbx.meta create mode 100644 Assets/Models/LowpolyTerrain.fbx create mode 100644 Assets/Models/LowpolyTerrain.fbx.meta create mode 100644 Assets/Models/Mushroom1.fbx create mode 100644 Assets/Models/Mushroom1.fbx.meta create mode 100644 Assets/Models/Mushroom2.fbx create mode 100644 Assets/Models/Mushroom2.fbx.meta create mode 100644 Assets/Models/MushroomLarge.fbx create mode 100644 Assets/Models/MushroomLarge.fbx.meta create mode 100644 Assets/Models/Paddle.fbx create mode 100644 Assets/Models/Paddle.fbx.meta create mode 100644 Assets/Models/Plant1.fbx create mode 100644 Assets/Models/Plant1.fbx.meta create mode 100644 Assets/Models/Plant2.fbx create mode 100644 Assets/Models/Plant2.fbx.meta create mode 100644 Assets/Models/Plant3.fbx create mode 100644 Assets/Models/Plant3.fbx.meta create mode 100644 Assets/Models/Plant4.fbx create mode 100644 Assets/Models/Plant4.fbx.meta create mode 100644 Assets/Models/Rock1.fbx create mode 100644 Assets/Models/Rock1.fbx.meta create mode 100644 Assets/Models/Rock10.fbx create mode 100644 Assets/Models/Rock10.fbx.meta create mode 100644 Assets/Models/Rock11.fbx create mode 100644 Assets/Models/Rock11.fbx.meta create mode 100644 Assets/Models/Rock12.fbx create mode 100644 Assets/Models/Rock12.fbx.meta create mode 100644 Assets/Models/Rock2.fbx create mode 100644 Assets/Models/Rock2.fbx.meta create mode 100644 Assets/Models/Rock3.fbx create mode 100644 Assets/Models/Rock3.fbx.meta create mode 100644 Assets/Models/Rock4.fbx create mode 100644 Assets/Models/Rock4.fbx.meta create mode 100644 Assets/Models/Rock5.fbx create mode 100644 Assets/Models/Rock5.fbx.meta create mode 100644 Assets/Models/Rock6.fbx create mode 100644 Assets/Models/Rock6.fbx.meta create mode 100644 Assets/Models/Rock7.fbx create mode 100644 Assets/Models/Rock7.fbx.meta create mode 100644 Assets/Models/Rock8.fbx create mode 100644 Assets/Models/Rock8.fbx.meta create mode 100644 Assets/Models/Rock9.fbx create mode 100644 Assets/Models/Rock9.fbx.meta create mode 100644 Assets/Models/Tent.fbx create mode 100644 Assets/Models/Tent.fbx.meta create mode 100644 Assets/Models/Tree1.fbx create mode 100644 Assets/Models/Tree1.fbx.meta create mode 100644 Assets/Models/Tree2.fbx create mode 100644 Assets/Models/Tree2.fbx.meta create mode 100644 Assets/Models/Tree3.fbx create mode 100644 Assets/Models/Tree3.fbx.meta create mode 100644 Assets/Models/TreeDead1.fbx create mode 100644 Assets/Models/TreeDead1.fbx.meta create mode 100644 Assets/Models/TreeDead2.fbx create mode 100644 Assets/Models/TreeDead2.fbx.meta create mode 100644 Assets/Models/TreeStump1.fbx create mode 100644 Assets/Models/TreeStump1.fbx.meta create mode 100644 Assets/Models/WoodBoat.fbx create mode 100644 Assets/Models/WoodBoat.fbx.meta create mode 100644 Assets/Models/WoodFence1.fbx create mode 100644 Assets/Models/WoodFence1.fbx.meta create mode 100644 Assets/Models/WoodFence2.fbx create mode 100644 Assets/Models/WoodFence2.fbx.meta create mode 100644 Assets/Prefabs.meta create mode 100644 Assets/Prefabs/Player.prefab create mode 100644 Assets/Prefabs/Player.prefab.meta create mode 100644 Assets/Readme.asset create mode 100644 Assets/Readme.asset.meta create mode 100644 Assets/Scenes.meta create mode 100644 Assets/Scenes/Game.unity create mode 100644 Assets/Scenes/Game.unity.meta create mode 100644 Assets/Scenes/GameOnline.unity create mode 100644 Assets/Scenes/GameOnline.unity.meta create mode 100644 Assets/Scenes/MainMenu.unity create mode 100644 Assets/Scenes/MainMenu.unity.meta create mode 100644 Assets/ScriptTemplates.meta create mode 100644 Assets/ScriptTemplates/50-Mirror__Network Manager-NewNetworkManager.cs.txt create mode 100644 Assets/ScriptTemplates/50-Mirror__Network Manager-NewNetworkManager.cs.txt.meta create mode 100644 Assets/ScriptTemplates/51-Mirror__Network Manager With Actions-NewNetworkManagerWithActions.cs.txt create mode 100644 Assets/ScriptTemplates/51-Mirror__Network Manager With Actions-NewNetworkManagerWithActions.cs.txt.meta create mode 100644 Assets/ScriptTemplates/52-Mirror__Network Authenticator-NewNetworkAuthenticator.cs.txt create mode 100644 Assets/ScriptTemplates/52-Mirror__Network Authenticator-NewNetworkAuthenticator.cs.txt.meta create mode 100644 Assets/ScriptTemplates/52-Mirror__Network Behaviour-NewNetworkBehaviour.cs.txt create mode 100644 Assets/ScriptTemplates/52-Mirror__Network Behaviour-NewNetworkBehaviour.cs.txt.meta create mode 100644 Assets/ScriptTemplates/53-Mirror__Network Behaviour With Actions-NewNetworkBehaviourWithActions.cs.txt create mode 100644 Assets/ScriptTemplates/53-Mirror__Network Behaviour With Actions-NewNetworkBehaviourWithActions.cs.txt.meta create mode 100644 Assets/ScriptTemplates/54-Mirror__Custom Interest Management-CustomInterestManagement.cs.txt create mode 100644 Assets/ScriptTemplates/54-Mirror__Custom Interest Management-CustomInterestManagement.cs.txt.meta create mode 100644 Assets/ScriptTemplates/54-Mirror__Network Room Manager-NewNetworkRoomManager.cs.txt create mode 100644 Assets/ScriptTemplates/54-Mirror__Network Room Manager-NewNetworkRoomManager.cs.txt.meta create mode 100644 Assets/ScriptTemplates/55-Mirror__Network Room Player-NewNetworkRoomPlayer.cs.txt create mode 100644 Assets/ScriptTemplates/55-Mirror__Network Room Player-NewNetworkRoomPlayer.cs.txt.meta create mode 100644 Assets/ScriptTemplates/56-Mirror__Network Discovery-NewNetworkDiscovery.cs.txt create mode 100644 Assets/ScriptTemplates/56-Mirror__Network Discovery-NewNetworkDiscovery.cs.txt.meta create mode 100644 Assets/ScriptTemplates/57-Mirror__Network Transform-NewNetworkTransform.cs.txt create mode 100644 Assets/ScriptTemplates/57-Mirror__Network Transform-NewNetworkTransform.cs.txt.meta create mode 100644 Assets/ScriptTemplates/Editor.meta create mode 100644 Assets/ScriptTemplates/Editor/MoveToAssetsFolder.cs create mode 100644 Assets/ScriptTemplates/Editor/MoveToAssetsFolder.cs.meta create mode 100644 Assets/Scripts.meta create mode 100644 Assets/Scripts/LobbyHandle.cs create mode 100644 Assets/Scripts/LobbyHandle.cs.meta create mode 100644 Assets/Scripts/MenuFunctions.cs create mode 100644 Assets/Scripts/MenuFunctions.cs.meta create mode 100644 Assets/Scripts/Movement.cs create mode 100644 Assets/Scripts/Movement.cs.meta create mode 100644 Assets/Scripts/PlayerCameraController.cs create mode 100644 Assets/Scripts/PlayerCameraController.cs.meta create mode 100644 Assets/Scripts/Steamworks.NET.meta create mode 100644 Assets/Scripts/Steamworks.NET/SteamManager.cs create mode 100644 Assets/Scripts/Steamworks.NET/SteamManager.cs.meta create mode 100644 Assets/Settings.meta create mode 100644 Assets/Settings/DefaultVolumeProfile.asset create mode 100644 Assets/Settings/DefaultVolumeProfile.asset.meta create mode 100644 Assets/Settings/Mobile_RPAsset.asset create mode 100644 Assets/Settings/Mobile_RPAsset.asset.meta create mode 100644 Assets/Settings/Mobile_Renderer.asset create mode 100644 Assets/Settings/Mobile_Renderer.asset.meta create mode 100644 Assets/Settings/PC_RPAsset.asset create mode 100644 Assets/Settings/PC_RPAsset.asset.meta create mode 100644 Assets/Settings/PC_Renderer.asset create mode 100644 Assets/Settings/PC_Renderer.asset.meta create mode 100644 Assets/Settings/SampleSceneProfile.asset create mode 100644 Assets/Settings/SampleSceneProfile.asset.meta create mode 100644 Assets/Settings/UniversalRenderPipelineGlobalSettings.asset create mode 100644 Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 Assets/TextMesh Pro.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Anton OFL.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Anton OFL.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Anton.ttf create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Anton.ttf.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Bangers - OFL.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Bangers - OFL.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Bangers.ttf create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Bangers.ttf.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Electronic Highway Sign.TTF create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Electronic Highway Sign.TTF.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Oswald-Bold - OFL.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Oswald-Bold - OFL.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Oswald-Bold.ttf create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Oswald-Bold.ttf.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold - AFL.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold - AFL.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold - License.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold - License.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold.ttf create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Roboto-Bold.ttf.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Unity - OFL.txt create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Unity - OFL.txt.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Unity.ttf create mode 100644 Assets/TextMesh Pro/Examples & Extras/Fonts/Unity.ttf.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Crate - Surface Shader Scene.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Crate - Surface Shader Scene.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Crate - URP.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Crate - URP.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - Logo Scene.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - Logo Scene.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - Surface Shader Scene.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - Surface Shader Scene.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - URP.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Ground - URP.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Small Crate_diffuse.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Materials/Small Crate_diffuse.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/Text Popup.prefab create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/Text Popup.prefab.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/TextMeshPro - Prefab 1.prefab create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/TextMeshPro - Prefab 1.prefab.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/TextMeshPro - Prefab 2.prefab create mode 100644 Assets/TextMesh Pro/Examples & Extras/Prefabs/TextMeshPro - Prefab 2.prefab.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Blue to Purple - Vertical.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Blue to Purple - Vertical.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Dark to Light Green - Vertical.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Dark to Light Green - Vertical.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Light to Dark Green - Vertical.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Light to Dark Green - Vertical.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Yellow to Orange - Vertical.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Color Gradient Presets/Yellow to Orange - Vertical.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Drop Shadow.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Drop Shadow.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Outline.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Outline.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Sunny Days.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF - Sunny Days.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Anton SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Drop Shadow - 2 Pass.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Drop Shadow - 2 Pass.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Drop Shadow.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Drop Shadow.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Outline.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF - Outline.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Glow.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Glow.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Logo - URP.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Logo - URP.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Logo.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF Logo.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Bangers SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Electronic Highway Sign SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Electronic Highway Sign SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Metalic Green.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Metalic Green.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Overlay.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Overlay.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Soft Mask.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/LiberationSans SDF - Soft Mask.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Oswald Bold SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Oswald Bold SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - Drop Shadow.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - Drop Shadow.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - HDRP Unlit.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - HDRP Unlit.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - Surface.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - Surface.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - URP.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF - URP.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Roboto-Bold SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF - HDRP LIT - Bloom.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF - HDRP LIT - Bloom.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF - HDRP LIT - Outline.mat create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF - HDRP LIT - Outline.mat.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Fonts & Materials/Unity SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Sprite Assets.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Sprite Assets/Default Sprite Asset.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Sprite Assets/Default Sprite Asset.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Sprite Assets/DropCap Numbers.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Resources/Sprite Assets/DropCap Numbers.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/01- Single Line TextMesh Pro.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/01- Single Line TextMesh Pro.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/02 - Multi-line TextMesh Pro.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/02 - Multi-line TextMesh Pro.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/03 - Line Justification.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/03 - Line Justification.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/04 - Word Wrapping.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/04 - Word Wrapping.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/05 - Style Tags.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/05 - Style Tags.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/06 - Extra Rich Text Examples.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/06 - Extra Rich Text Examples.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/07 - Superscript & Subscript Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/07 - Superscript & Subscript Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/08 - Improved Text Alignment.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/08 - Improved Text Alignment.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/09 - Margin Tag Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/09 - Margin Tag Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/10 - Bullets & Numbered List Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/10 - Bullets & Numbered List Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/11 - The Style Tag.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/11 - The Style Tag.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/12 - Link Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/12 - Link Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/12a - Text Interactions.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/12a - Text Interactions.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/13 - Soft Hyphenation.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/13 - Soft Hyphenation.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/14 - Multi Font & Sprites.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/14 - Multi Font & Sprites.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/15 - Inline Graphics & Sprites.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/15 - Inline Graphics & Sprites.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/16 - Linked text overflow mode example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/16 - Linked text overflow mode example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/17 - Old Computer Terminal.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/17 - Old Computer Terminal.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/18 - ScrollRect & Masking & Layout.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/18 - ScrollRect & Masking & Layout.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/19 - Masking Texture & Soft Mask.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/19 - Masking Texture & Soft Mask.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/20 - Input Field with Scrollbar.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/20 - Input Field with Scrollbar.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/21 - Script Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/21 - Script Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/22 - Basic Scripting Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/22 - Basic Scripting Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/23 - Animating Vertex Attributes.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/23 - Animating Vertex Attributes.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/24 - Surface Shader Example URP.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/24 - Surface Shader Example URP.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/24 - Surface Shader Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/24 - Surface Shader Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/25 - Sunny Days Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/25 - Sunny Days Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/26 - Dropdown Placeholder Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/26 - Dropdown Placeholder Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/27 - Double Pass Shader Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/27 - Double Pass Shader Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/28 - HDRP Shader Example.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/28 - HDRP Shader Example.unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/28 - HDRP Shader Example.unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/28 - HDRP Shader Example/Sky and Fog Volume Profile.asset create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/28 - HDRP Shader Example/Sky and Fog Volume Profile.asset.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/Benchmark (Floating Text).unity create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scenes/Benchmark (Floating Text).unity.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark01.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark01.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark01_UGUI.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark01_UGUI.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark02.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark02.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark03.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark03.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark04.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/Benchmark04.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/CameraController.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/CameraController.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ChatController.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ChatController.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/DropdownSample.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/DropdownSample.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/EnvMapAnimator.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/EnvMapAnimator.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ObjectSpin.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ObjectSpin.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ShaderPropAnimator.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/ShaderPropAnimator.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/SimpleScript.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/SimpleScript.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/SkewTextExample.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/SkewTextExample.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_DigitValidator.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_DigitValidator.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_ExampleScript_01.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_ExampleScript_01.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_FrameRateCounter.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_FrameRateCounter.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_PhoneNumberValidator.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_PhoneNumberValidator.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextEventCheck.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextEventCheck.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextEventHandler.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextEventHandler.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextInfoDebugTool.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextInfoDebugTool.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextSelector_A.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextSelector_A.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextSelector_B.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_TextSelector_B.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_UiFrameRateCounter.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMP_UiFrameRateCounter.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMPro_InstructionOverlay.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TMPro_InstructionOverlay.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TeleType.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TeleType.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextConsoleSimulator.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextConsoleSimulator.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextMeshProFloatingText.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextMeshProFloatingText.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextMeshSpawner.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/TextMeshSpawner.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexColorCycler.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexColorCycler.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexJitter.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexJitter.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexShakeA.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexShakeA.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexShakeB.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexShakeB.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexZoom.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/VertexZoom.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/WarpTextExample.cs create mode 100644 Assets/TextMesh Pro/Examples & Extras/Scripts/WarpTextExample.cs.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Sprites.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Sprites/Default Sprites.png create mode 100644 Assets/TextMesh Pro/Examples & Extras/Sprites/Default Sprites.png.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Sprites/DropCap Numbers.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Sprites/DropCap Numbers.psd.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Brushed Metal 3.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Brushed Metal 3.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Floor Cement.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Floor Cement.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Floor Tiles 1 - diffuse.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Floor Tiles 1 - diffuse.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Fruit Jelly (B&W).jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Fruit Jelly (B&W).jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Diagonal (Color).jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Diagonal (Color).jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Horizontal (Color).jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Horizontal (Color).jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Vertical (Color).jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Gradient Vertical (Color).jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Mask Zig-n-Zag.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Mask Zig-n-Zag.psd.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Small Crate_diffuse.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Small Crate_diffuse.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Small Crate_normal.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Small Crate_normal.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Sunny Days - Seamless.jpg create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Sunny Days - Seamless.jpg.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Text Overflow - Linked Text Image 1.png create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Text Overflow - Linked Text Image 1.png.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Text Overflow - Linked Text UI Screenshot.png create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Text Overflow - Linked Text UI Screenshot.png.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Circle.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Circle.psd.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Diagonal.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Diagonal.psd.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Radial Double.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Radial Double.psd.meta create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Radial Quad.psd create mode 100644 Assets/TextMesh Pro/Examples & Extras/Textures/Wipe Pattern - Radial Quad.psd.meta create mode 100644 Assets/TextMesh Pro/Fonts.meta create mode 100644 Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt create mode 100644 Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt.meta create mode 100644 Assets/TextMesh Pro/Fonts/LiberationSans.ttf create mode 100644 Assets/TextMesh Pro/Fonts/LiberationSans.ttf.meta create mode 100644 Assets/TextMesh Pro/Resources.meta create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials.meta create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Drop Shadow.mat create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Drop Shadow.mat.meta create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset.meta create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Outline.mat create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Outline.mat.meta create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset create mode 100644 Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset.meta create mode 100644 Assets/TextMesh Pro/Resources/LineBreaking Following Characters.txt create mode 100644 Assets/TextMesh Pro/Resources/LineBreaking Following Characters.txt.meta create mode 100644 Assets/TextMesh Pro/Resources/LineBreaking Leading Characters.txt create mode 100644 Assets/TextMesh Pro/Resources/LineBreaking Leading Characters.txt.meta create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets.meta create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/EmojiOne.asset create mode 100644 Assets/TextMesh Pro/Resources/Sprite Assets/EmojiOne.asset.meta create mode 100644 Assets/TextMesh Pro/Resources/Style Sheets.meta create mode 100644 Assets/TextMesh Pro/Resources/Style Sheets/Default Style Sheet.asset create mode 100644 Assets/TextMesh Pro/Resources/Style Sheets/Default Style Sheet.asset.meta create mode 100644 Assets/TextMesh Pro/Resources/TMP Settings.asset create mode 100644 Assets/TextMesh Pro/Resources/TMP Settings.asset.meta create mode 100644 Assets/TextMesh Pro/Shaders.meta create mode 100644 Assets/TextMesh Pro/Shaders/SDFFunctions.hlsl create mode 100644 Assets/TextMesh Pro/Shaders/SDFFunctions.hlsl.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap-Custom-Atlas.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap-Custom-Atlas.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap-Mobile.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap-Mobile.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Bitmap.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF Overlay.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF Overlay.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF SSD.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF SSD.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP LIT.shadergraph create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP LIT.shadergraph.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP UNLIT.shadergraph create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP UNLIT.shadergraph.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Masking.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Masking.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Overlay.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Overlay.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile SSD.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile SSD.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile-2-Pass.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile-2-Pass.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Surface-Mobile.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Surface-Mobile.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Surface.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-Surface.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-URP Lit.shadergraph create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-URP Lit.shadergraph.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-URP Unlit.shadergraph create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF-URP Unlit.shadergraph.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_SDF.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Sprite.shader create mode 100644 Assets/TextMesh Pro/Shaders/TMP_Sprite.shader.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMPro.cginc create mode 100644 Assets/TextMesh Pro/Shaders/TMPro.cginc.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Mobile.cginc create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Mobile.cginc.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Properties.cginc create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Properties.cginc.meta create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Surface.cginc create mode 100644 Assets/TextMesh Pro/Shaders/TMPro_Surface.cginc.meta create mode 100644 Assets/TextMesh Pro/Sprites.meta create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne Attribution.txt create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne Attribution.txt.meta create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne.json create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne.json.meta create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne.png create mode 100644 Assets/TextMesh Pro/Sprites/EmojiOne.png.meta create mode 100644 Assets/com.rlabrecque.steamworks.net.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/RedistCopy.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/RedistCopy.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/RedistInstall.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/RedistInstall.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/com.rlabrecque.steamworks.net.editor.asmdef create mode 100644 Assets/com.rlabrecque.steamworks.net/Editor/com.rlabrecque.steamworks.net.editor.asmdef.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/LICENSE.md create mode 100644 Assets/com.rlabrecque.steamworks.net/LICENSE.md.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/libsteam_api.so create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/libsteam_api.so.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.bundle.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.bundle/Contents.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.bundle/Contents/Info.plist create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.bundle/Contents/MacOS.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.bundle/Contents/MacOS/libsteam_api.dylib create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.dll create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api.dll.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api64.dll create mode 100644 Assets/com.rlabrecque.steamworks.net/Plugins/steam_api64.dll.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/README.md create mode 100644 Assets/com.rlabrecque.steamworks.net/README.md.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/CallbackDispatcher.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/CallbackDispatcher.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/CallbackIdentity.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/CallbackIdentity.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/ISteamMatchmakingResponses.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/ISteamMatchmakingResponses.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/InteropHelp.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/InteropHelp.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Packsize.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Packsize.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Steam.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Steam.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Version.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/Version.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/NativeMethods.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/NativeMethods.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamCallbacks.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamCallbacks.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamConstants.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamConstants.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamEnums.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamEnums.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamStructs.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/SteamStructs.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamapps.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamapps.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamclient.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamclient.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamfriends.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamfriends.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserver.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserver.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverclient.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverclient.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverhttp.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverhttp.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverinventory.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverinventory.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworking.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworking.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingmessages.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingmessages.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingsockets.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingsockets.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingutils.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameservernetworkingutils.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverstats.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverstats.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverugc.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverugc.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverutils.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamgameserverutils.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamhtmlsurface.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamhtmlsurface.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamhttp.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamhttp.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteaminput.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteaminput.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteaminventory.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteaminventory.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammatchmaking.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammatchmaking.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammusic.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammusic.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammusicremote.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteammusicremote.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworking.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworking.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingmessages.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingmessages.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingsockets.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingsockets.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingutils.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamnetworkingutils.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamparentalsettings.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamparentalsettings.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamremoteplay.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamremoteplay.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamremotestorage.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamremotestorage.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamscreenshots.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamscreenshots.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamtimeline.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamtimeline.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamugc.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamugc.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamuser.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamuser.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamuserstats.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamuserstats.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamutils.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamutils.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamvideo.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/autogen/isteamvideo.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/com.rlabrecque.steamworks.net.asmdef create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/com.rlabrecque.steamworks.net.asmdef.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/MatchmakingTypes.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/MatchmakingTypes/gameserveritem_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/MatchmakingTypes/gameserveritem_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/MatchmakingTypes/servernetadr_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/MatchmakingTypes/servernetadr_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClient.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClient/SteamAPIWarningMessageHook_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClient/SteamAPIWarningMessageHook_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClient/SteamAPI_CheckCallbackRegistered_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClient/SteamAPI_CheckCallbackRegistered_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/CGameID.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/CGameID.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/CSteamID.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/CSteamID.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/HAuthTicket.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamClientPublic/HAuthTicket.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamDatagramTickets.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamDatagramTickets/SteamDatagramHostedAddress.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamDatagramTickets/SteamDatagramHostedAddress.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamDatagramTickets/SteamDatagramRelayAuthTicket.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamDatagramTickets/SteamDatagramRelayAuthTicket.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamFriends.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamFriends/FriendsGroupID_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamFriends/FriendsGroupID_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTMLSurface.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTMLSurface/HHTMLBrowser.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTMLSurface/HHTMLBrowser.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTTP.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTTP/HTTPCookieContainerHandle.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTTP/HTTPCookieContainerHandle.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTTP/HTTPRequestHandle.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamHTTP/HTTPRequestHandle.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputActionSetHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputActionSetHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputAnalogActionHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputAnalogActionHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputDigitalActionHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputDigitalActionHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/InputHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/SteamInputActionEventCallbackPointer.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/SteamInputActionEventCallbackPointer.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/SteamInputActionEvent_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInput/SteamInputActionEvent_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamInventoryResult_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamInventoryResult_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamInventoryUpdateHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamInventoryUpdateHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamItemDef_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamItemDef_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamItemInstanceID_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamInventory/SteamItemInstanceID_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamMatchmaking.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamMatchmaking/HServerListRequest.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamMatchmaking/HServerListRequest.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamMatchmaking/HServerQuery.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamMatchmaking/HServerQuery.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworking.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworking/SNetListenSocket_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworking/SNetListenSocket_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworking/SNetSocket_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworking/SNetSocket_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingSockets.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingSockets/ISteamNetworkingConnectionSignaling.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingSockets/ISteamNetworkingConnectionSignaling.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingSockets/ISteamNetworkingSignalingRecvContext.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingSockets/ISteamNetworkingSignalingRecvContext.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/FSteamNetworkingSocketsDebugOutput.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/FSteamNetworkingSocketsDebugOutput.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamListenSocket.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamListenSocket.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamNetConnection.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamNetConnection.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamNetPollGroup.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/HSteamNetPollGroup.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingConfigValue_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingConfigValue_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingErrMsg.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingErrMsg.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingIPAddr.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingIPAddr.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingIdentity.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingIdentity.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingMessage_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingMessage_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingMicroseconds.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingMicroseconds.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingPOPID.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamNetworkingTypes/SteamNetworkingPOPID.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemotePlay.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemotePlay/RemotePlaySessionID_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemotePlay/RemotePlaySessionID_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/PublishedFileId_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/PublishedFileId_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/PublishedFileUpdateHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/PublishedFileUpdateHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/UGCFileWriteStreamHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/UGCFileWriteStreamHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/UGCHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamRemoteStorage/UGCHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamScreenshots.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamScreenshots/ScreenshotHandle.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamScreenshots/ScreenshotHandle.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/AccountID_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/AccountID_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/AppId_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/AppId_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/DepotId_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/DepotId_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/PartyBeaconID_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/PartyBeaconID_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/RTime32.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/RTime32.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/SteamAPICall_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/SteamAPICall_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/SteamIPAddress_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamTypes/SteamIPAddress_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUGC.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUGC/UGCQueryHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUGC/UGCQueryHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUGC/UGCUpdateHandle_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUGC/UGCUpdateHandle_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUserStats.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUserStats/SteamLeaderboardEntries_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUserStats/SteamLeaderboardEntries_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUserStats/SteamLeaderboard_t.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/SteamUserStats/SteamLeaderboard_t.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/Steam_api_common.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/Steam_api_common/HSteamPipe.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/Steam_api_common/HSteamPipe.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/Steam_api_common/HSteamUser.cs create mode 100644 Assets/com.rlabrecque.steamworks.net/Runtime/types/Steam_api_common/HSteamUser.cs.meta create mode 100644 Assets/com.rlabrecque.steamworks.net/package.json create mode 100644 Assets/com.rlabrecque.steamworks.net/package.json.meta create mode 100644 Assets/images.meta create mode 100644 Assets/images/IMG_0149.jpg create mode 100644 Assets/images/IMG_0149.jpg.meta create mode 100644 Assets/images/hyprland.png create mode 100644 Assets/images/hyprland.png.meta create mode 100644 Packages/manifest.json create mode 100644 Packages/packages-lock.json create mode 100644 ProjectSettings/AudioManager.asset create mode 100644 ProjectSettings/ClusterInputManager.asset create mode 100644 ProjectSettings/DynamicsManager.asset create mode 100644 ProjectSettings/EditorBuildSettings.asset create mode 100644 ProjectSettings/EditorSettings.asset create mode 100644 ProjectSettings/GraphicsSettings.asset create mode 100644 ProjectSettings/InputManager.asset create mode 100644 ProjectSettings/MemorySettings.asset create mode 100644 ProjectSettings/MultiplayerManager.asset create mode 100644 ProjectSettings/NavMeshAreas.asset create mode 100644 ProjectSettings/PackageManagerSettings.asset create mode 100644 ProjectSettings/Physics2DSettings.asset create mode 100644 ProjectSettings/PresetManager.asset create mode 100644 ProjectSettings/ProjectSettings.asset create mode 100644 ProjectSettings/ProjectVersion.txt create mode 100644 ProjectSettings/QualitySettings.asset create mode 100644 ProjectSettings/SceneTemplateSettings.json create mode 100644 ProjectSettings/ShaderGraphSettings.asset create mode 100644 ProjectSettings/TagManager.asset create mode 100644 ProjectSettings/TimeManager.asset create mode 100644 ProjectSettings/URPProjectSettings.asset create mode 100644 ProjectSettings/UnityConnectSettings.asset create mode 100644 ProjectSettings/VFXManager.asset create mode 100644 ProjectSettings/VersionControlSettings.asset create mode 100644 ProjectSettings/XRSettings.asset create mode 100644 ignore.conf create mode 100644 steam_appid.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5993314 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +Library +library +Temp +temp +Obj +obj +Build +build +Builds +builds +UserSettings +usersettings +MemoryCaptures +memorycaptures +Logs +logs +**/Assets/AssetStoreTools +**/assets/assetstoretools +/Assets/Plugins/PlasticSCM* +/assets/plugins/PlasticSCM* +*.private +*.private.meta +^*.private.[0-9]+$ +^*.private.[0-9]+.meta$ +.vs +.vscode +.idea +.gradle +ExportedObj +.consulo +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db +*.pidb.meta +*.pdb.meta +*.mdb.meta +sysinfo.txt +crashlytics-build.properties +*.apk +*.aab +*.app +*.unitypackage +~UnityDirMonSyncFile~* +**/Assets/AddressableAssetsData/*/*.bin* +**/assets/addressableassetsdata/*/*.bin* +**/Assets/StreamingAssets/aa.meta +**/assets/streamingassets/*/aa/* +.DS_Store* +Thumbs.db +Desktop.ini \ No newline at end of file diff --git a/.plastic/plastic.changes b/.plastic/plastic.changes new file mode 100644 index 0000000000000000000000000000000000000000..858ad925056b37974b33171a834825c8b05f80f0 GIT binary patch literal 462290 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

XPNbyHb6qZWLiaJ@=E3wFgOX-M#u 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 literal 0 HcmV?d00001 diff --git a/.plastic/plastic.workspace b/.plastic/plastic.workspace new file mode 100644 index 0000000..0307a1d --- /dev/null +++ b/.plastic/plastic.workspace @@ -0,0 +1,2 @@ +Survival Game +c0ca5767-b2f2-4c3a-938c-001a07ad39c8 diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions new file mode 100644 index 0000000..1a12cb9 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions @@ -0,0 +1,1057 @@ +{ + "name": "InputSystem_Actions", + "maps": [ + { + "name": "Player", + "id": "df70fa95-8a34-4494-b137-73ab6b9c7d37", + "actions": [ + { + "name": "Move", + "type": "Value", + "id": "351f2ccd-1f9f-44bf-9bec-d62ac5c5f408", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Look", + "type": "Value", + "id": "6b444451-8a00-4d00-a97e-f47457f736a8", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Attack", + "type": "Button", + "id": "6c2ab1b8-8984-453a-af3d-a3c78ae1679a", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Interact", + "type": "Button", + "id": "852140f2-7766-474d-8707-702459ba45f3", + "expectedControlType": "Button", + "processors": "", + "interactions": "Hold", + "initialStateCheck": false + }, + { + "name": "Crouch", + "type": "Button", + "id": "27c5f898-bc57-4ee1-8800-db469aca5fe3", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Jump", + "type": "Button", + "id": "f1ba0d36-48eb-4cd5-b651-1c94a6531f70", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Previous", + "type": "Button", + "id": "2776c80d-3c14-4091-8c56-d04ced07a2b0", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Next", + "type": "Button", + "id": "b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Sprint", + "type": "Button", + "id": "641cd816-40e6-41b4-8c3d-04687c349290", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "978bfe49-cc26-4a3d-ab7b-7d7a29327403", + "path": "/leftStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "WASD", + "id": "00ca640b-d935-4593-8157-c05846ea39b3", + "path": "Dpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "e2062cb9-1b15-46a2-838c-2f8d72a0bdd9", + "path": "/w", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "8180e8bd-4097-4f4e-ab88-4523101a6ce9", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "320bffee-a40b-4347-ac70-c210eb8bc73a", + "path": "/s", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "1c5327b5-f71c-4f60-99c7-4e737386f1d1", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "d2581a9b-1d11-4566-b27d-b92aff5fabbc", + "path": "/a", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "2e46982e-44cc-431b-9f0b-c11910bf467a", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcfe95b8-67b9-4526-84b5-5d0bc98d6400", + "path": "/d", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "77bff152-3580-4b21-b6de-dcd0c7e41164", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8", + "path": "/{Primary2DAxis}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3ea4d645-4504-4529-b061-ab81934c3752", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c1f7a91b-d0fd-4a62-997e-7fb9b69bf235", + "path": "/rightStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8c8e490b-c610-4785-884f-f04217b23ca4", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse;Touch", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3e5f5442-8668-4b27-a940-df99bad7e831", + "path": "/{Hatswitch}", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "143bb1cd-cc10-4eca-a2f0-a3664166fe91", + "path": "/buttonWest", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "05f6913d-c316-48b2-a6bb-e225f14c7960", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "886e731e-7071-4ae4-95c0-e61739dad6fd", + "path": "/primaryTouch/tap", + "interactions": "", + "processors": "", + "groups": ";Touch", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ee3d0cd2-254e-47a7-a8cb-bc94d9658c54", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8255d333-5683-4943-a58a-ccb207ff1dce", + "path": "/{PrimaryAction}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3c1c7f0-bd20-4ee7-a0f1-899b24bca6d7", + "path": "/enter", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cbac6039-9c09-46a1-b5f2-4e5124ccb5ed", + "path": "/2", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e15ca19d-e649-4852-97d5-7fe8ccc44e94", + "path": "/dpad/right", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "f2e9ba44-c423-42a7-ad56-f20975884794", + "path": "/leftShift", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8cbb2f4b-a784-49cc-8d5e-c010b8c7f4e6", + "path": "/leftStickPress", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d8bf24bf-3f2f-4160-a97c-38ec1eb520ba", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "eb40bb66-4559-4dfa-9a2f-820438abb426", + "path": "/space", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "daba33a1-ad0c-4742-a909-43ad1cdfbeb6", + "path": "/buttonSouth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "603f3daf-40bd-4854-8724-93e8017f59e3", + "path": "/secondaryButton", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1534dc16-a6aa-499d-9c3a-22b47347b52a", + "path": "/1", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "25060bbd-a3a6-476e-8fba-45ae484aad05", + "path": "/dpad/left", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1c04ea5f-b012-41d1-a6f7-02e963b52893", + "path": "/e", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3f66d0b-7751-423f-908b-a11c5bd95930", + "path": "/buttonNorth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4f4649ac-64a8-4a73-af11-b3faef356a4d", + "path": "/buttonEast", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "36e52cba-0905-478e-a818-f4bfcb9f3b9a", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + } + ] + }, + { + "name": "UI", + "id": "272f6d14-89ba-496f-b7ff-215263d3219f", + "actions": [ + { + "name": "Navigate", + "type": "PassThrough", + "id": "c95b2375-e6d9-4b88-9c4c-c5e76515df4b", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Submit", + "type": "Button", + "id": "7607c7b6-cd76-4816-beef-bd0341cfe950", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Cancel", + "type": "Button", + "id": "15cef263-9014-4fd5-94d9-4e4a6234a6ef", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Point", + "type": "PassThrough", + "id": "32b35790-4ed0-4e9a-aa41-69ac6d629449", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Click", + "type": "PassThrough", + "id": "3c7022bf-7922-4f7c-a998-c437916075ad", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "RightClick", + "type": "PassThrough", + "id": "44b200b1-1557-4083-816c-b22cbdf77ddf", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "MiddleClick", + "type": "PassThrough", + "id": "dad70c86-b58c-4b17-88ad-f5e53adf419e", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ScrollWheel", + "type": "PassThrough", + "id": "0489e84a-4833-4c40-bfae-cea84b696689", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDevicePosition", + "type": "PassThrough", + "id": "24908448-c609-4bc3-a128-ea258674378a", + "expectedControlType": "Vector3", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDeviceOrientation", + "type": "PassThrough", + "id": "9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be", + "expectedControlType": "Quaternion", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "Gamepad", + "id": "809f371f-c5e2-4e7a-83a1-d867598f40dd", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "14a5d6e8-4aaf-4119-a9ef-34b8c2c548bf", + "path": "/leftStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "9144cbe6-05e1-4687-a6d7-24f99d23dd81", + "path": "/rightStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2db08d65-c5fb-421b-983f-c71163608d67", + "path": "/leftStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "58748904-2ea9-4a80-8579-b500e6a76df8", + "path": "/rightStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "8ba04515-75aa-45de-966d-393d9bbd1c14", + "path": "/leftStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "712e721c-bdfb-4b23-a86c-a0d9fcfea921", + "path": "/rightStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcd248ae-a788-4676-a12e-f4d81205600b", + "path": "/leftStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "1f04d9bc-c50b-41a1-bfcc-afb75475ec20", + "path": "/rightStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "fb8277d4-c5cd-4663-9dc7-ee3f0b506d90", + "path": "/dpad", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "Joystick", + "id": "e25d9774-381c-4a61-b47c-7b6b299ad9f9", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "3db53b26-6601-41be-9887-63ac74e79d19", + "path": "/stick/up", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "0cb3e13e-3d90-4178-8ae6-d9c5501d653f", + "path": "/stick/down", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "0392d399-f6dd-4c82-8062-c1e9c0d34835", + "path": "/stick/left", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "942a66d9-d42f-43d6-8d70-ecb4ba5363bc", + "path": "/stick/right", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "Keyboard", + "id": "ff527021-f211-4c02-933e-5976594c46ed", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "563fbfdd-0f09-408d-aa75-8642c4f08ef0", + "path": "/w", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "eb480147-c587-4a33-85ed-eb0ab9942c43", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2bf42165-60bc-42ca-8072-8c13ab40239b", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "85d264ad-e0a0-4565-b7ff-1a37edde51ac", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "74214943-c580-44e4-98eb-ad7eebe17902", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "cea9b045-a000-445b-95b8-0c171af70a3b", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "8607c725-d935-4808-84b1-8354e29bab63", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "4cda81dc-9edd-4e03-9d7c-a71a14345d0b", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "9e92bb26-7e3b-4ec4-b06b-3c8f8e498ddc", + "path": "*/{Submit}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "82627dcc-3b13-4ba9-841d-e4b746d6553e", + "path": "*/{Cancel}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c52c8e0b-8179-41d3-b8a1-d149033bbe86", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e1394cbc-336e-44ce-9ea8-6007ed6193f7", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "5693e57a-238a-46ed-b5ae-e64e6e574302", + "path": "/touch*/position", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4faf7dc9-b979-4210-aa8c-e808e1ef89f5", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8d66d5ba-88d7-48e6-b1cd-198bbfef7ace", + "path": "/tip", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "47c2a644-3ebc-4dae-a106-589b7ca75b59", + "path": "/touch*/press", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "bb9e6b34-44bf-4381-ac63-5aa15d19f677", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "38c99815-14ea-4617-8627-164d27641299", + "path": "/scroll", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ScrollWheel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4c191405-5738-4d4b-a523-c6a301dbf754", + "path": "/rightButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "RightClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "24066f69-da47-44f3-a07e-0015fb02eb2e", + "path": "/middleButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "MiddleClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "7236c0d9-6ca3-47cf-a6ee-a97f5b59ea77", + "path": "/devicePosition", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDevicePosition", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "23e01e3a-f935-4948-8d8b-9bcac77714fb", + "path": "/deviceRotation", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDeviceOrientation", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Assets/InputSystem_Actions.inputactions.meta b/Assets/InputSystem_Actions.inputactions.meta new file mode 100644 index 0000000..6b38b04 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 052faaac586de48259a63d0c4782560b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: diff --git a/Assets/Materials.meta b/Assets/Materials.meta new file mode 100644 index 0000000..b0df44b --- /dev/null +++ b/Assets/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3285be480b55bcc41af2063e1d870bc1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/CloudMat.mat b/Assets/Materials/CloudMat.mat new file mode 100644 index 0000000..502d288 --- /dev/null +++ b/Assets/Materials/CloudMat.mat @@ -0,0 +1,136 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: CloudMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &5080578154030464470 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/CloudMat.mat.meta b/Assets/Materials/CloudMat.mat.meta new file mode 100644 index 0000000..caf0f7e --- /dev/null +++ b/Assets/Materials/CloudMat.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51adf49c828af4b42b49cd399cd49b10 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/DemoPlaneMat.mat b/Assets/Materials/DemoPlaneMat.mat new file mode 100644 index 0000000..4bccfbf --- /dev/null +++ b/Assets/Materials/DemoPlaneMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: DemoPlaneMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &6249695203784365348 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/DemoPlaneMat.mat.meta b/Assets/Materials/DemoPlaneMat.mat.meta new file mode 100644 index 0000000..6c25eed --- /dev/null +++ b/Assets/Materials/DemoPlaneMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: d598d01c3db68c94692eb5c44c83de93 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/DemoPlaneMat.mat + uploadId: 355026 diff --git a/Assets/Materials/EmissionBlueMat.mat b/Assets/Materials/EmissionBlueMat.mat new file mode 100644 index 0000000..0bdafd8 --- /dev/null +++ b/Assets/Materials/EmissionBlueMat.mat @@ -0,0 +1,139 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-1361300781669679935 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: EmissionBlueMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _EMISSION + m_InvalidKeywords: [] + m_LightmapFlags: 1 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0, g: 0.34901962, b: 1, a: 1} + - _Color: {r: 0, g: 0.3490196, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 2.792157, b: 5.992157, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/EmissionBlueMat.mat.meta b/Assets/Materials/EmissionBlueMat.mat.meta new file mode 100644 index 0000000..68d593f --- /dev/null +++ b/Assets/Materials/EmissionBlueMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5a42f8033becfcc4db580e9dd08bd6b3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/EmissionBlueMat.mat + uploadId: 355026 diff --git a/Assets/Materials/EmissionYellowMat.mat b/Assets/Materials/EmissionYellowMat.mat new file mode 100644 index 0000000..b816006 --- /dev/null +++ b/Assets/Materials/EmissionYellowMat.mat @@ -0,0 +1,139 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7340924476660754128 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: EmissionYellowMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _EMISSION + m_InvalidKeywords: [] + m_LightmapFlags: 1 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.654902, b: 0, a: 1} + - _Color: {r: 1, g: 0.654902, b: 0, a: 1} + - _EmissionColor: {r: 11.984314, g: 7.2156863, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/EmissionYellowMat.mat.meta b/Assets/Materials/EmissionYellowMat.mat.meta new file mode 100644 index 0000000..d2c59ad --- /dev/null +++ b/Assets/Materials/EmissionYellowMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: a23517422c44285409996ebf0584f793 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/EmissionYellowMat.mat + uploadId: 355026 diff --git a/Assets/Materials/Flower1.mat b/Assets/Materials/Flower1.mat new file mode 100644 index 0000000..519ea38 --- /dev/null +++ b/Assets/Materials/Flower1.mat @@ -0,0 +1,136 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Flower1 + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.654902, b: 0, a: 1} + - _Color: {r: 1, g: 0.654902, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &3032102260634984014 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/Flower1.mat.meta b/Assets/Materials/Flower1.mat.meta new file mode 100644 index 0000000..c47e68d --- /dev/null +++ b/Assets/Materials/Flower1.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fbae7d0a7cc14941bd25d1420265239 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Flower2Mat.mat b/Assets/Materials/Flower2Mat.mat new file mode 100644 index 0000000..fd266da --- /dev/null +++ b/Assets/Materials/Flower2Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Flower2Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.8901961, b: 0.30588236, a: 1} + - _Color: {r: 1, g: 0.8901961, b: 0.30588233, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &302073328569408989 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/Flower2Mat.mat.meta b/Assets/Materials/Flower2Mat.mat.meta new file mode 100644 index 0000000..e95fd54 --- /dev/null +++ b/Assets/Materials/Flower2Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 1c5a335489a263f458754f8cde45f221 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Flower2Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Flower3Mat.mat b/Assets/Materials/Flower3Mat.mat new file mode 100644 index 0000000..e619efd --- /dev/null +++ b/Assets/Materials/Flower3Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Flower3Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.50980395, g: 0.19215687, b: 1, a: 1} + - _Color: {r: 0.5098039, g: 0.19215682, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &5839876351184463291 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/Flower3Mat.mat.meta b/Assets/Materials/Flower3Mat.mat.meta new file mode 100644 index 0000000..b74af5b --- /dev/null +++ b/Assets/Materials/Flower3Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: ef2c3380ea506a54a96b15b9518d303e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Flower3Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Flower4Mat.mat b/Assets/Materials/Flower4Mat.mat new file mode 100644 index 0000000..e03f32f --- /dev/null +++ b/Assets/Materials/Flower4Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-4666988055523656634 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Flower4Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Flower4Mat.mat.meta b/Assets/Materials/Flower4Mat.mat.meta new file mode 100644 index 0000000..daac468 --- /dev/null +++ b/Assets/Materials/Flower4Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: b043653feafde9a498c209b65e6b09a7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Flower4Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Mushroom1Mat.mat b/Assets/Materials/Mushroom1Mat.mat new file mode 100644 index 0000000..76c4a31 --- /dev/null +++ b/Assets/Materials/Mushroom1Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Mushroom1Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.9529412, g: 0.62352943, b: 0.07450981, a: 1} + - _Color: {r: 0.9529411, g: 0.62352943, b: 0.07450979, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &8273787286697982776 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/Mushroom1Mat.mat.meta b/Assets/Materials/Mushroom1Mat.mat.meta new file mode 100644 index 0000000..657aed7 --- /dev/null +++ b/Assets/Materials/Mushroom1Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5835797300e10724eb31a26fa6baa1a6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Mushroom1Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Mushroom2Mat.mat b/Assets/Materials/Mushroom2Mat.mat new file mode 100644 index 0000000..a7c5230 --- /dev/null +++ b/Assets/Materials/Mushroom2Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-6531324179032325065 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Mushroom2Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.13725491, b: 0, a: 1} + - _Color: {r: 1, g: 0.13725486, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Mushroom2Mat.mat.meta b/Assets/Materials/Mushroom2Mat.mat.meta new file mode 100644 index 0000000..37fa30a --- /dev/null +++ b/Assets/Materials/Mushroom2Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 308680fc3656cdb49aa30c04aae1eb87 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Mushroom2Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Mushroom3Mat.mat b/Assets/Materials/Mushroom3Mat.mat new file mode 100644 index 0000000..1d26953 --- /dev/null +++ b/Assets/Materials/Mushroom3Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-1895889940820185893 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Mushroom3Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.49411765, g: 0.13725491, b: 0.62352943, a: 1} + - _Color: {r: 0.49411762, g: 0.13725486, b: 0.62352943, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Mushroom3Mat.mat.meta b/Assets/Materials/Mushroom3Mat.mat.meta new file mode 100644 index 0000000..3dbac76 --- /dev/null +++ b/Assets/Materials/Mushroom3Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 23f92ab09af350146b1d22ca67ed7887 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Mushroom3Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/PlantMat.mat b/Assets/Materials/PlantMat.mat new file mode 100644 index 0000000..157b49a --- /dev/null +++ b/Assets/Materials/PlantMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: PlantMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.42745098, g: 0.69803923, b: 0.16078432, a: 1} + - _Color: {r: 0.42745095, g: 0.69803923, b: 0.16078427, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &5066488160649396432 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/PlantMat.mat.meta b/Assets/Materials/PlantMat.mat.meta new file mode 100644 index 0000000..0e8ffa4 --- /dev/null +++ b/Assets/Materials/PlantMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 49f2ecb08a0c38140b335a0a1f7f66f4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/PlantMat.mat + uploadId: 355026 diff --git a/Assets/Materials/RockMat.mat b/Assets/Materials/RockMat.mat new file mode 100644 index 0000000..b4d5808 --- /dev/null +++ b/Assets/Materials/RockMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-3860915453833832309 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RockMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.7058824, g: 0.70980394, b: 0.7490196, a: 1} + - _Color: {r: 0.7058824, g: 0.70980394, b: 0.7490196, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/RockMat.mat.meta b/Assets/Materials/RockMat.mat.meta new file mode 100644 index 0000000..16d4aab --- /dev/null +++ b/Assets/Materials/RockMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5bfbfdebccebf0c45832bef70d1337f7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/RockMat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreeGreen1Mat.mat b/Assets/Materials/TreeGreen1Mat.mat new file mode 100644 index 0000000..12d7dda --- /dev/null +++ b/Assets/Materials/TreeGreen1Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreeGreen1Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.3019608, g: 0.59607846, b: 0.15294118, a: 1} + - _Color: {r: 0.30196077, g: 0.5960784, b: 0.15294114, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &3847857020129133202 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/TreeGreen1Mat.mat.meta b/Assets/Materials/TreeGreen1Mat.mat.meta new file mode 100644 index 0000000..dd7f2c6 --- /dev/null +++ b/Assets/Materials/TreeGreen1Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: cf7b2a2a4b5c2bb409c794db9d64ff3f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreeGreen1Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreeGreen2Mat.mat b/Assets/Materials/TreeGreen2Mat.mat new file mode 100644 index 0000000..3531464 --- /dev/null +++ b/Assets/Materials/TreeGreen2Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8079581851252746576 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreeGreen2Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.3019608, g: 0.59607846, b: 0.15294118, a: 1} + - _Color: {r: 0.30196077, g: 0.5960784, b: 0.15294114, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/TreeGreen2Mat.mat.meta b/Assets/Materials/TreeGreen2Mat.mat.meta new file mode 100644 index 0000000..a9b7361 --- /dev/null +++ b/Assets/Materials/TreeGreen2Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: b6747bf277df0e344ac544c7cfa37c62 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreeGreen2Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreeOrangeMat.mat b/Assets/Materials/TreeOrangeMat.mat new file mode 100644 index 0000000..eea8bab --- /dev/null +++ b/Assets/Materials/TreeOrangeMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreeOrangeMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.9254902, g: 0.6, b: 0.1254902, a: 1} + - _Color: {r: 0.9254902, g: 0.6, b: 0.12549016, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &8055897138333884152 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/TreeOrangeMat.mat.meta b/Assets/Materials/TreeOrangeMat.mat.meta new file mode 100644 index 0000000..57541ea --- /dev/null +++ b/Assets/Materials/TreeOrangeMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 33535d2d31f89e846b6ec7c60219cb96 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreeOrangeMat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreePinkMat.mat b/Assets/Materials/TreePinkMat.mat new file mode 100644 index 0000000..55c5178 --- /dev/null +++ b/Assets/Materials/TreePinkMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreePinkMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.44705883, b: 0.6745098, a: 1} + - _Color: {r: 1, g: 0.4470588, b: 0.6745098, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &5974931177563081965 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/TreePinkMat.mat.meta b/Assets/Materials/TreePinkMat.mat.meta new file mode 100644 index 0000000..989b46b --- /dev/null +++ b/Assets/Materials/TreePinkMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: e8231e5e093c804458795712745c4041 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreePinkMat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreeRedMat.mat b/Assets/Materials/TreeRedMat.mat new file mode 100644 index 0000000..c115434 --- /dev/null +++ b/Assets/Materials/TreeRedMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreeRedMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.8745098, g: 0.4392157, b: 1, a: 1} + - _Color: {r: 0.8745098, g: 0.43921566, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &2337907632141962616 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/TreeRedMat.mat.meta b/Assets/Materials/TreeRedMat.mat.meta new file mode 100644 index 0000000..a29e274 --- /dev/null +++ b/Assets/Materials/TreeRedMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: f154dff7fb489d2499686dc9f08c626a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreeRedMat.mat + uploadId: 355026 diff --git a/Assets/Materials/TreeYellowMat.mat b/Assets/Materials/TreeYellowMat.mat new file mode 100644 index 0000000..0c926b7 --- /dev/null +++ b/Assets/Materials/TreeYellowMat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TreeYellowMat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 0.84313726, b: 0.19215687, a: 1} + - _Color: {r: 1, g: 0.8431372, b: 0.19215682, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &9096231894155169978 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 diff --git a/Assets/Materials/TreeYellowMat.mat.meta b/Assets/Materials/TreeYellowMat.mat.meta new file mode 100644 index 0000000..0d19bfa --- /dev/null +++ b/Assets/Materials/TreeYellowMat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 1b3799f72f9aa654d9f7a3787feef4ee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/TreeYellowMat.mat + uploadId: 355026 diff --git a/Assets/Materials/Wood1Mat.mat b/Assets/Materials/Wood1Mat.mat new file mode 100644 index 0000000..e72e672 --- /dev/null +++ b/Assets/Materials/Wood1Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-5042034021279010468 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Wood1Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.69803923, g: 0.42745098, b: 0.16862746, a: 1} + - _Color: {r: 0.69803923, g: 0.42745095, b: 0.16862741, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Wood1Mat.mat.meta b/Assets/Materials/Wood1Mat.mat.meta new file mode 100644 index 0000000..0f3b339 --- /dev/null +++ b/Assets/Materials/Wood1Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 57f391477e46ecd44af6579114e37dfb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Wood1Mat.mat + uploadId: 355026 diff --git a/Assets/Materials/Wood2Mat.mat b/Assets/Materials/Wood2Mat.mat new file mode 100644 index 0000000..42d555f --- /dev/null +++ b/Assets/Materials/Wood2Mat.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-2563699239131985293 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 9 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Wood2Mat + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _UVSec: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.85882354, g: 0.72156864, b: 0.57254905, a: 1} + - _Color: {r: 0.85882354, g: 0.72156864, b: 0.57254905, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Wood2Mat.mat.meta b/Assets/Materials/Wood2Mat.mat.meta new file mode 100644 index 0000000..4fe873b --- /dev/null +++ b/Assets/Materials/Wood2Mat.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 983007e3e230f954187baf11f58a929d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 157552 + packageName: Simple Low Poly Nature Pack + packageVersion: 1.2 + assetPath: Assets/SimpleLowPolyNature/Materials/Wood2Mat.mat + uploadId: 355026 diff --git a/Assets/Mirror.meta b/Assets/Mirror.meta new file mode 100644 index 0000000..649f2f4 --- /dev/null +++ b/Assets/Mirror.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c9f8dc0aab937744b75430053b820e6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Authenticators.meta b/Assets/Mirror/Authenticators.meta new file mode 100644 index 0000000..644f4ec --- /dev/null +++ b/Assets/Mirror/Authenticators.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b2f9d254154cd942ba40b06b869b8f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs b/Assets/Mirror/Authenticators/BasicAuthenticator.cs new file mode 100644 index 0000000..92ff68c --- /dev/null +++ b/Assets/Mirror/Authenticators/BasicAuthenticator.cs @@ -0,0 +1,192 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Authenticators +{ + [AddComponentMenu("Network/ Authenticators/Basic Authenticator")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-authenticators/basic-authenticator")] + public class BasicAuthenticator : NetworkAuthenticator + { + [Header("Server Credentials")] + public string serverUsername; + public string serverPassword; + + [Header("Client Credentials")] + public string username; + public string password; + + readonly HashSet connectionsPendingDisconnect = new HashSet(); + + #region Messages + + public struct AuthRequestMessage : NetworkMessage + { + // use whatever credentials make sense for your game + // for example, you might want to pass the accessToken if using oauth + public string authUsername; + public string authPassword; + } + + public struct AuthResponseMessage : NetworkMessage + { + public byte code; + public string message; + } + + #endregion + + #region Server + + ///

+ /// Called on server from StartServer to initialize the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStartServer() + { + // register a handler for the authentication request we expect from client + NetworkServer.RegisterHandler(OnAuthRequestMessage, false); + } + + /// + /// Called on server from StopServer to reset the Authenticator + /// Server message handlers should be unregistered in this method. + /// + public override void OnStopServer() + { + // unregister the handler for the authentication request + NetworkServer.UnregisterHandler(); + } + + /// + /// Called on server from OnServerConnectInternal when a client needs to authenticate + /// + /// Connection to client. + public override void OnServerAuthenticate(NetworkConnectionToClient conn) + { + // do nothing...wait for AuthRequestMessage from client + } + + /// + /// Called on server when the client's AuthRequestMessage arrives + /// + /// Connection to client. + /// The message payload + public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) + { + //Debug.Log($"Authentication Request: {msg.authUsername} {msg.authPassword}"); + + if (connectionsPendingDisconnect.Contains(conn)) return; + + // check the credentials by calling your web server, database table, playfab api, or any method appropriate. + if (msg.authUsername == serverUsername && msg.authPassword == serverPassword) + { + // create and send msg to client so it knows to proceed + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 100, + message = "Success" + }; + + conn.Send(authResponseMessage); + + // Accept the successful authentication + ServerAccept(conn); + } + else + { + connectionsPendingDisconnect.Add(conn); + + // create and send msg to client so it knows to disconnect + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 200, + message = "Invalid Credentials" + }; + + conn.Send(authResponseMessage); + + // must set NetworkConnection isAuthenticated = false + conn.isAuthenticated = false; + + // disconnect the client after 1 second so that response message gets delivered + StartCoroutine(DelayedDisconnect(conn, 1f)); + } + } + + IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime) + { + yield return new WaitForSeconds(waitTime); + + // Reject the unsuccessful authentication + ServerReject(conn); + + yield return null; + + // remove conn from pending connections + connectionsPendingDisconnect.Remove(conn); + } + + #endregion + + #region Client + + /// + /// Called on client from StartClient to initialize the Authenticator + /// Client message handlers should be registered in this method. + /// + public override void OnStartClient() + { + // register a handler for the authentication response we expect from server + NetworkClient.RegisterHandler(OnAuthResponseMessage, false); + } + + /// + /// Called on client from StopClient to reset the Authenticator + /// Client message handlers should be unregistered in this method. + /// + public override void OnStopClient() + { + // unregister the handler for the authentication response + NetworkClient.UnregisterHandler(); + } + + /// + /// Called on client from OnClientConnectInternal when a client needs to authenticate + /// + public override void OnClientAuthenticate() + { + AuthRequestMessage authRequestMessage = new AuthRequestMessage + { + authUsername = username, + authPassword = password + }; + + NetworkClient.Send(authRequestMessage); + } + + /// + /// Called on client when the server's AuthResponseMessage arrives + /// + /// The message payload + public void OnAuthResponseMessage(AuthResponseMessage msg) + { + if (msg.code == 100) + { + //Debug.Log($"Authentication Response: {msg.message}"); + + // Authentication has been accepted + ClientAccept(); + } + else + { + Debug.LogError($"Authentication Response: {msg.message}"); + + // Authentication has been rejected + ClientReject(); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta b/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta new file mode 100644 index 0000000..d4581cf --- /dev/null +++ b/Assets/Mirror/Authenticators/BasicAuthenticator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 28496b776660156428f00cf78289c1ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Authenticators/BasicAuthenticator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Authenticators/DeviceAuthenticator.cs b/Assets/Mirror/Authenticators/DeviceAuthenticator.cs new file mode 100644 index 0000000..5e0ea56 --- /dev/null +++ b/Assets/Mirror/Authenticators/DeviceAuthenticator.cs @@ -0,0 +1,129 @@ +using System; +using UnityEngine; + +namespace Mirror.Authenticators +{ + /// + /// An authenticator that identifies the user by their device. + /// A GUID is used as a fallback when the platform doesn't support SystemInfo.deviceUniqueIdentifier. + /// Note: deviceUniqueIdentifier can be spoofed, so security is not guaranteed. + /// See https://docs.unity3d.com/ScriptReference/SystemInfo-deviceUniqueIdentifier.html for details. + /// + [AddComponentMenu("Network/ Authenticators/Device Authenticator")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-authenticators/device-authenticator")] + public class DeviceAuthenticator : NetworkAuthenticator + { + #region Messages + + public struct AuthRequestMessage : NetworkMessage + { + public string clientDeviceID; + } + + public struct AuthResponseMessage : NetworkMessage { } + + #endregion + + #region Server + + /// + /// Called on server from StartServer to initialize the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStartServer() + { + // register a handler for the authentication request we expect from client + NetworkServer.RegisterHandler(OnAuthRequestMessage, false); + } + + /// + /// Called on server from StopServer to reset the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStopServer() + { + // unregister the handler for the authentication request + NetworkServer.UnregisterHandler(); + } + + /// + /// Called on server from OnServerConnectInternal when a client needs to authenticate + /// + /// Connection to client. + public override void OnServerAuthenticate(NetworkConnectionToClient conn) + { + // do nothing, wait for client to send his id + } + + void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) + { + Debug.Log($"connection {conn.connectionId} authenticated with id {msg.clientDeviceID}"); + + // Store the device id for later reference, e.g. when spawning the player + conn.authenticationData = msg.clientDeviceID; + + // Send a response to client telling it to proceed as authenticated + conn.Send(new AuthResponseMessage()); + + // Accept the successful authentication + ServerAccept(conn); + } + + #endregion + + #region Client + + /// + /// Called on client from StartClient to initialize the Authenticator + /// Client message handlers should be registered in this method. + /// + public override void OnStartClient() + { + // register a handler for the authentication response we expect from server + NetworkClient.RegisterHandler(OnAuthResponseMessage, false); + } + + /// + /// Called on client from StopClient to reset the Authenticator + /// Client message handlers should be unregistered in this method. + /// + public override void OnStopClient() + { + // unregister the handler for the authentication response + NetworkClient.UnregisterHandler(); + } + + /// + /// Called on client from OnClientConnectInternal when a client needs to authenticate + /// + public override void OnClientAuthenticate() + { + string deviceUniqueIdentifier = SystemInfo.deviceUniqueIdentifier; + + // Not all platforms support this, so we use a GUID instead + if (deviceUniqueIdentifier == SystemInfo.unsupportedIdentifier) + { + // Get the value from PlayerPrefs if it exists, new GUID if it doesn't + deviceUniqueIdentifier = PlayerPrefs.GetString("deviceUniqueIdentifier", Guid.NewGuid().ToString()); + + // Store the deviceUniqueIdentifier to PlayerPrefs (in case we just made a new GUID) + PlayerPrefs.SetString("deviceUniqueIdentifier", deviceUniqueIdentifier); + } + + // send the deviceUniqueIdentifier to the server + NetworkClient.Send(new AuthRequestMessage { clientDeviceID = deviceUniqueIdentifier } ); + } + + /// + /// Called on client when the server's AuthResponseMessage arrives + /// + /// The message payload + public void OnAuthResponseMessage(AuthResponseMessage msg) + { + Debug.Log("Authentication Success"); + ClientAccept(); + } + + #endregion + } +} diff --git a/Assets/Mirror/Authenticators/DeviceAuthenticator.cs.meta b/Assets/Mirror/Authenticators/DeviceAuthenticator.cs.meta new file mode 100644 index 0000000..3c115ca --- /dev/null +++ b/Assets/Mirror/Authenticators/DeviceAuthenticator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 60960a6ba81a842deb2fdcdc93788242 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Authenticators/DeviceAuthenticator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef new file mode 100644 index 0000000..70eacf3 --- /dev/null +++ b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Mirror.Authenticators", + "rootNamespace": "", + "references": [ + "GUID:30817c1a0e6d646d99c048fc403f5979" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta new file mode 100644 index 0000000..af5d5bd --- /dev/null +++ b/Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e720aa64e3f58fb4880566a322584340 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Authenticators/Mirror.Authenticators.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs new file mode 100644 index 0000000..711ee6e --- /dev/null +++ b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs @@ -0,0 +1,70 @@ +using System.Collections; +using UnityEngine; + +namespace Mirror.Authenticators +{ + /// + /// An authenticator that disconnects connections if they don't + /// authenticate within a specified time limit. + /// + [AddComponentMenu("Network/ Authenticators/Timeout Authenticator")] + public class TimeoutAuthenticator : NetworkAuthenticator + { + public NetworkAuthenticator authenticator; + + [Range(0, 600), Tooltip("Timeout to auto-disconnect in seconds. Set to 0 for no timeout.")] + public float timeout = 60; + + public void Awake() + { + authenticator.OnServerAuthenticated.AddListener(connection => OnServerAuthenticated.Invoke(connection)); + authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated.Invoke); + } + + public override void OnStartServer() + { + authenticator.OnStartServer(); + } + + public override void OnStopServer() + { + authenticator.OnStopServer(); + } + + public override void OnStartClient() + { + authenticator.OnStartClient(); + } + + public override void OnStopClient() + { + authenticator.OnStopClient(); + } + + public override void OnServerAuthenticate(NetworkConnectionToClient conn) + { + authenticator.OnServerAuthenticate(conn); + if (timeout > 0) + StartCoroutine(BeginAuthentication(conn)); + } + + public override void OnClientAuthenticate() + { + authenticator.OnClientAuthenticate(); + if (timeout > 0) + StartCoroutine(BeginAuthentication(NetworkClient.connection)); + } + + IEnumerator BeginAuthentication(NetworkConnection conn) + { + //Debug.Log($"Authentication countdown started {conn} {timeout}"); + yield return new WaitForSecondsRealtime(timeout); + + if (!conn.isAuthenticated) + { + Debug.LogError($"Authentication Timeout - Disconnecting {conn}"); + conn.Disconnect(); + } + } + } +} diff --git a/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta new file mode 100644 index 0000000..a2d3a37 --- /dev/null +++ b/Assets/Mirror/Authenticators/TimeoutAuthenticator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 24d8269a07b8e4edfa374753a91c946e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Authenticators/TimeoutAuthenticator.cs + uploadId: 736421 diff --git a/Assets/Mirror/CompilerSymbols.meta b/Assets/Mirror/CompilerSymbols.meta new file mode 100644 index 0000000..4652ae1 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f8b918bcd89f5c488b06f5574f34760 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef new file mode 100644 index 0000000..af25622 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Mirror.CompilerSymbols", + "references": [], + "optionalUnityReferences": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta new file mode 100644 index 0000000..a58bca4 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 325984b52e4128546bc7558552f8b1d2 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/CompilerSymbols/Mirror.CompilerSymbols.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs new file mode 100644 index 0000000..26aff41 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using UnityEditor; + +namespace Mirror +{ + static class PreprocessorDefine + { + /// + /// Add define symbols as soon as Unity gets done compiling. + /// + [InitializeOnLoadMethod] + public static void AddDefineSymbols() + { +#if UNITY_2021_2_OR_NEWER + string currentDefines = PlayerSettings.GetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup)); +#else + // Deprecated in Unity 2023.1 + string currentDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); +#endif + // Remove oldest when adding next month's symbol. + // Keep a rolling 12 months of symbols. + HashSet defines = new HashSet(currentDefines.Split(';')) + { + "MIRROR", + "MIRROR_89_OR_NEWER", + "MIRROR_90_OR_NEWER", + "MIRROR_93_OR_NEWER", + "MIRROR_96_OR_NEWER" + }; + + // only touch PlayerSettings if we actually modified it, + // otherwise it shows up as changed in git each time. + string newDefines = string.Join(";", defines); + if (newDefines != currentDefines) + { +#if UNITY_2021_2_OR_NEWER + PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup), newDefines); +#else + // Deprecated in Unity 2023.1 + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); +#endif + } + } + } +} diff --git a/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta new file mode 100644 index 0000000..27860f5 --- /dev/null +++ b/Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f1d66fe74ec6f42dd974cba37d25d453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/CompilerSymbols/PreprocessorDefine.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components.meta b/Assets/Mirror/Components.meta new file mode 100644 index 0000000..c2771d9 --- /dev/null +++ b/Assets/Mirror/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9bee879fbc8ef4b1a9a9f7088bfbf726 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/AssemblyInfo.cs b/Assets/Mirror/Components/AssemblyInfo.cs new file mode 100644 index 0000000..f342716 --- /dev/null +++ b/Assets/Mirror/Components/AssemblyInfo.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Mirror.Tests.Common")] +[assembly: InternalsVisibleTo("Mirror.Tests")] +// need to use Unity.*.CodeGen assembly name to import Unity.CompilationPipeline +// for ILPostProcessor tests. +[assembly: InternalsVisibleTo("Unity.Mirror.Tests.CodeGen")] +[assembly: InternalsVisibleTo("Mirror.Tests.Generated")] +[assembly: InternalsVisibleTo("Mirror.Tests.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Editor")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Editor")] diff --git a/Assets/Mirror/Components/AssemblyInfo.cs.meta b/Assets/Mirror/Components/AssemblyInfo.cs.meta new file mode 100644 index 0000000..565e5cb --- /dev/null +++ b/Assets/Mirror/Components/AssemblyInfo.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a65b9283f7a724e70b8e17cb277f4c1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/AssemblyInfo.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Discovery.meta b/Assets/Mirror/Components/Discovery.meta new file mode 100644 index 0000000..d5bb0cb --- /dev/null +++ b/Assets/Mirror/Components/Discovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5dcf9618f5e14a4eb60bff5480284a6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs new file mode 100644 index 0000000..5fa9397 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs @@ -0,0 +1,93 @@ +using System; +using System.Net; +using UnityEngine; +using UnityEngine.Events; + +namespace Mirror.Discovery +{ + [Serializable] + public class ServerFoundUnityEvent : UnityEvent {}; + + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Discovery")] + public class NetworkDiscovery : NetworkDiscoveryBase + { + #region Server + + /// + /// Process the request from a client + /// + /// + /// Override if you wish to provide more information to the clients + /// such as the name of the host player + /// + /// Request coming from client + /// Address of the client that sent the request + /// The message to be sent back to the client or null + protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoint endpoint) + { + // In this case we don't do anything with the request + // but other discovery implementations might want to use the data + // in there, This way the client can ask for + // specific game mode or something + + try + { + // this is an example reply message, return your own + // to include whatever is relevant for your game + return new ServerResponse + { + serverId = ServerId, + uri = transport.ServerUri() + }; + } + catch (NotImplementedException) + { + Debug.LogError($"Transport {transport} does not support network discovery"); + throw; + } + } + + #endregion + + #region Client + + /// + /// Create a message that will be broadcasted on the network to discover servers + /// + /// + /// Override if you wish to include additional data in the discovery message + /// such as desired game mode, language, difficulty, etc... + /// An instance of ServerRequest with data to be broadcasted + protected override ServerRequest GetRequest() => new ServerRequest(); + + /// + /// Process the answer from a server + /// + /// + /// A client receives a reply from a server, this method processes the + /// reply and raises an event + /// + /// Response that came from the server + /// Address of the server that replied + protected override void ProcessResponse(ServerResponse response, IPEndPoint endpoint) + { + // we received a message from the remote endpoint + response.EndPoint = endpoint; + + // although we got a supposedly valid url, we may not be able to resolve + // the provided host + // However we know the real ip address of the server because we just + // received a packet from it, so use that as host. + UriBuilder realUri = new UriBuilder(response.uri) + { + Host = response.EndPoint.Address.ToString() + }; + response.uri = realUri.Uri; + + OnServerFound.Invoke(response); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta new file mode 100644 index 0000000..c6c23e0 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscovery.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c761308e733c51245b2e8bb4201f46dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Discovery/NetworkDiscovery.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs new file mode 100644 index 0000000..677bad3 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs @@ -0,0 +1,473 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using UnityEngine; + +// Based on https://github.com/EnlightenedOne/MirrorNetworkDiscovery +// forked from https://github.com/in0finite/MirrorNetworkDiscovery +// Both are MIT Licensed + +namespace Mirror.Discovery +{ + /// + /// Base implementation for Network Discovery. Extend this component + /// to provide custom discovery with game specific data + /// NetworkDiscovery for a sample implementation + /// + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-discovery")] + public abstract class NetworkDiscoveryBase : MonoBehaviour + where Request : NetworkMessage + where Response : NetworkMessage + { + public static bool SupportedOnThisPlatform { get { return Application.platform != RuntimePlatform.WebGLPlayer; } } + + [SerializeField] + [Tooltip("If true, broadcasts a discovery request every ActiveDiscoveryInterval seconds")] + public bool enableActiveDiscovery = true; + + // broadcast address needs to be configurable on iOS: + // https://github.com/vis2k/Mirror/pull/3255 + [Tooltip("iOS may require LAN IP address here (e.g. 192.168.x.x), otherwise leave blank.")] + public string BroadcastAddress = ""; + + [SerializeField] + [Tooltip("The UDP port the server will listen for multi-cast messages")] + protected int serverBroadcastListenPort = 47777; + + [SerializeField] + [Tooltip("Time in seconds between multi-cast messages")] + [Range(1, 60)] + float ActiveDiscoveryInterval = 3; + + [Tooltip("Transport to be advertised during discovery")] + public Transport transport; + + [Tooltip("Invoked when a server is found")] + public ServerFoundUnityEvent OnServerFound; + + // Each game should have a random unique handshake, + // this way you can tell if this is the same game or not + [HideInInspector] + public long secretHandshake; + + public long ServerId { get; private set; } + + protected UdpClient serverUdpClient; + protected UdpClient clientUdpClient; + +#if UNITY_EDITOR + public virtual void OnValidate() + { + if (transport == null) + transport = GetComponent(); + + if (secretHandshake == 0) + { + secretHandshake = RandomLong(); + UnityEditor.Undo.RecordObject(this, "Set secret handshake"); + } + } +#endif + + /// + /// virtual so that inheriting classes' Start() can call base.Start() too + /// + public virtual void Start() + { + ServerId = RandomLong(); + + // active transport gets initialized in Awake + // so make sure we set it here in Start() after Awake + // Or just let the user assign it in the inspector + if (transport == null) + transport = Transport.active; + + // Server mode? then start advertising + if (Utils.IsHeadless()) + { + AdvertiseServer(); + } + } + + public static long RandomLong() + { + int value1 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); + int value2 = UnityEngine.Random.Range(int.MinValue, int.MaxValue); + return value1 + ((long)value2 << 32); + } + + // Ensure the ports are cleared no matter when Game/Unity UI exits + void OnApplicationQuit() + { + //Debug.Log("NetworkDiscoveryBase OnApplicationQuit"); + Shutdown(); + } + + void OnDisable() + { + //Debug.Log("NetworkDiscoveryBase OnDisable"); + Shutdown(); + } + + void OnDestroy() + { + //Debug.Log("NetworkDiscoveryBase OnDestroy"); + Shutdown(); + } + + void Shutdown() + { + EndpMulticastLock(); + if (serverUdpClient != null) + { + try + { + serverUdpClient.Close(); + } + catch (Exception) + { + // it is just close, swallow the error + } + + serverUdpClient = null; + } + + if (clientUdpClient != null) + { + try + { + clientUdpClient.Close(); + } + catch (Exception) + { + // it is just close, swallow the error + } + + clientUdpClient = null; + } + + CancelInvoke(); + } + + #region Server + + /// + /// Advertise this server in the local network + /// + public void AdvertiseServer() + { + if (!SupportedOnThisPlatform) + throw new PlatformNotSupportedException("Network discovery not supported in this platform"); + + StopDiscovery(); + + // Setup port -- may throw exception + serverUdpClient = new UdpClient(serverBroadcastListenPort) + { + EnableBroadcast = true, + MulticastLoopback = false + }; + + //Debug.Log($"Discovery: Advertising Server {Dns.GetHostName()}"); + + // listen for client pings + _ = ServerListenAsync(); + } + + public async Task ServerListenAsync() + { + BeginMulticastLock(); + while (true) + { + try + { + await ReceiveRequestAsync(serverUdpClient); + } + catch (ObjectDisposedException) + { + // socket has been closed + break; + } + catch (Exception) {} + } + } + + async Task ReceiveRequestAsync(UdpClient udpClient) + { + // only proceed if there is available data in network buffer, or otherwise Receive() will block + // average time for UdpClient.Available : 10 us + + UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); + + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(udpReceiveResult.Buffer)) + { + long handshake = networkReader.ReadLong(); + if (handshake != secretHandshake) + { + // message is not for us + throw new ProtocolViolationException("Invalid handshake"); + } + + Request request = networkReader.Read(); + + ProcessClientRequest(request, udpReceiveResult.RemoteEndPoint); + } + } + + /// + /// Reply to the client to inform it of this server + /// + /// + /// Override if you wish to ignore server requests based on + /// custom criteria such as language, full server game mode or difficulty + /// + /// Request coming from client + /// Address of the client that sent the request + protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint) + { + Response info = ProcessRequest(request, endpoint); + + if (info == null) + return; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + try + { + writer.WriteLong(secretHandshake); + + writer.Write(info); + + ArraySegment data = writer.ToArraySegment(); + // signature matches + // send response + serverUdpClient.Send(data.Array, data.Count, endpoint); + } + catch (Exception ex) + { + Debug.LogException(ex, this); + } + } + } + + /// + /// Process the request from a client + /// + /// + /// Override if you wish to provide more information to the clients + /// such as the name of the host player + /// + /// Request coming from client + /// Address of the client that sent the request + /// The message to be sent back to the client or null + protected abstract Response ProcessRequest(Request request, IPEndPoint endpoint); + + // Android Multicast fix: https://github.com/vis2k/Mirror/pull/2887 +#if UNITY_ANDROID + AndroidJavaObject multicastLock; + bool hasMulticastLock; +#endif + + void BeginMulticastLock() + { +#if UNITY_ANDROID + if (hasMulticastLock) return; + + if (Application.platform == RuntimePlatform.Android) + { + using (AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic("currentActivity")) + { + using (var wifiManager = activity.Call("getSystemService", "wifi")) + { + multicastLock = wifiManager.Call("createMulticastLock", "lock"); + multicastLock.Call("acquire"); + hasMulticastLock = true; + } + } + } +#endif + } + + void EndpMulticastLock() + { +#if UNITY_ANDROID + if (!hasMulticastLock) return; + + multicastLock?.Call("release"); + hasMulticastLock = false; +#endif + } + +#endregion + + #region Client + + /// + /// Start Active Discovery + /// + public void StartDiscovery() + { + if (!SupportedOnThisPlatform) + throw new PlatformNotSupportedException("Network discovery not supported in this platform"); + + StopDiscovery(); + + try + { + // Setup port + clientUdpClient = new UdpClient(0) + { + EnableBroadcast = true, + MulticastLoopback = false + }; + } + catch (Exception) + { + // Free the port if we took it + //Debug.LogError("NetworkDiscoveryBase StartDiscovery Exception"); + Shutdown(); + throw; + } + + _ = ClientListenAsync(); + + if (enableActiveDiscovery) InvokeRepeating(nameof(BroadcastDiscoveryRequest), 0, ActiveDiscoveryInterval); + } + + /// + /// Stop Active Discovery + /// + public void StopDiscovery() + { + //Debug.Log("NetworkDiscoveryBase StopDiscovery"); + Shutdown(); + } + + /// + /// Awaits for server response + /// + /// ClientListenAsync Task + public async Task ClientListenAsync() + { + // while clientUpdClient to fix: + // https://github.com/vis2k/Mirror/pull/2908 + // + // If, you cancel discovery the clientUdpClient is set to null. + // However, nothing cancels ClientListenAsync. If we change the if(true) + // to check if the client is null. You can properly cancel the discovery, + // and kill the listen thread. + // + // Prior to this fix, if you cancel the discovery search. It crashes the + // thread, and is super noisy in the output. As well as causes issues on + // the quest. + while (clientUdpClient != null) + { + try + { + await ReceiveGameBroadcastAsync(clientUdpClient); + } + catch (ObjectDisposedException) + { + // socket was closed, no problem + return; + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + } + + /// + /// Sends discovery request from client + /// + public void BroadcastDiscoveryRequest() + { + if (clientUdpClient == null) + return; + + if (NetworkClient.isConnected) + { + StopDiscovery(); + return; + } + + IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, serverBroadcastListenPort); + + if (!string.IsNullOrWhiteSpace(BroadcastAddress)) + { + try + { + endPoint = new IPEndPoint(IPAddress.Parse(BroadcastAddress), serverBroadcastListenPort); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + writer.WriteLong(secretHandshake); + + try + { + Request request = GetRequest(); + + writer.Write(request); + + ArraySegment data = writer.ToArraySegment(); + + //Debug.Log($"Discovery: Sending BroadcastDiscoveryRequest {request}"); + clientUdpClient.SendAsync(data.Array, data.Count, endPoint); + } + catch (Exception) + { + // It is ok if we can't broadcast to one of the addresses + } + } + } + + /// + /// Create a message that will be broadcasted on the network to discover servers + /// + /// + /// Override if you wish to include additional data in the discovery message + /// such as desired game mode, language, difficulty, etc... + /// An instance of ServerRequest with data to be broadcasted + protected virtual Request GetRequest() => default; + + async Task ReceiveGameBroadcastAsync(UdpClient udpClient) + { + // only proceed if there is available data in network buffer, or otherwise Receive() will block + // average time for UdpClient.Available : 10 us + + UdpReceiveResult udpReceiveResult = await udpClient.ReceiveAsync(); + + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(udpReceiveResult.Buffer)) + { + if (networkReader.ReadLong() != secretHandshake) + return; + + Response response = networkReader.Read(); + + ProcessResponse(response, udpReceiveResult.RemoteEndPoint); + } + } + + /// + /// Process the answer from a server + /// + /// + /// A client receives a reply from a server, this method processes the + /// reply and raises an event + /// + /// Response that came from the server + /// Address of the server that replied + protected abstract void ProcessResponse(Response response, IPEndPoint endpoint); + + #endregion + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta new file mode 100644 index 0000000..cbd7616 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b9971d60ce61f4e39b07cd9e7e0c68fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Discovery/NetworkDiscoveryBase.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs new file mode 100644 index 0000000..a34bbe0 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Mirror.Discovery +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Discovery HUD")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-discovery")] + [RequireComponent(typeof(NetworkDiscovery))] + public class NetworkDiscoveryHUD : MonoBehaviour + { + readonly Dictionary discoveredServers = new Dictionary(); + Vector2 scrollViewPos = Vector2.zero; + + public NetworkDiscovery networkDiscovery; + +#if UNITY_EDITOR + void OnValidate() + { + if (Application.isPlaying) return; + Reset(); + } + + void Reset() + { + networkDiscovery = GetComponent(); + + // Add default event handler if not already present + if (!Enumerable.Range(0, networkDiscovery.OnServerFound.GetPersistentEventCount()) + .Any(i => networkDiscovery.OnServerFound.GetPersistentMethodName(i) == nameof(OnDiscoveredServer))) + { + UnityEditor.Events.UnityEventTools.AddPersistentListener(networkDiscovery.OnServerFound, OnDiscoveredServer); + UnityEditor.Undo.RecordObjects(new UnityEngine.Object[] { this, networkDiscovery }, "Set NetworkDiscovery"); + } + } +#endif + + void OnGUI() + { + if (NetworkManager.singleton == null) + return; + + if (!NetworkClient.isConnected && !NetworkServer.active && !NetworkClient.active) + DrawGUI(); + + if (NetworkServer.active || NetworkClient.active) + StopButtons(); + } + + void DrawGUI() + { + GUILayout.BeginArea(new Rect(10, 10, 300, 500)); + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Find Servers")) + { + discoveredServers.Clear(); + networkDiscovery.StartDiscovery(); + } + + // LAN Host + if (GUILayout.Button("Start Host")) + { + discoveredServers.Clear(); + NetworkManager.singleton.StartHost(); + networkDiscovery.AdvertiseServer(); + } + + // Dedicated server + if (GUILayout.Button("Start Server")) + { + discoveredServers.Clear(); + NetworkManager.singleton.StartServer(); + networkDiscovery.AdvertiseServer(); + } + + GUILayout.EndHorizontal(); + + // show list of found server + + GUILayout.Label($"Discovered Servers [{discoveredServers.Count}]:"); + + // servers + scrollViewPos = GUILayout.BeginScrollView(scrollViewPos); + + foreach (ServerResponse info in discoveredServers.Values) + if (GUILayout.Button(info.EndPoint.Address.ToString())) + Connect(info); + + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } + + void StopButtons() + { + GUILayout.BeginArea(new Rect(10, 40, 100, 25)); + + // stop host if host mode + if (NetworkServer.active && NetworkClient.isConnected) + { + if (GUILayout.Button("Stop Host")) + { + NetworkManager.singleton.StopHost(); + networkDiscovery.StopDiscovery(); + } + } + // stop client if client-only + else if (NetworkClient.isConnected) + { + if (GUILayout.Button("Stop Client")) + { + NetworkManager.singleton.StopClient(); + networkDiscovery.StopDiscovery(); + } + } + // stop server if server-only + else if (NetworkServer.active) + { + if (GUILayout.Button("Stop Server")) + { + NetworkManager.singleton.StopServer(); + networkDiscovery.StopDiscovery(); + } + } + + GUILayout.EndArea(); + } + + void Connect(ServerResponse info) + { + networkDiscovery.StopDiscovery(); + NetworkManager.singleton.StartClient(info.uri); + } + + public void OnDiscoveredServer(ServerResponse info) + { + Debug.Log($"Discovered Server: {info.serverId} | {info.EndPoint} | {info.uri}"); + + // Note that you can check the versioning to decide if you can connect to the server or not using this method + discoveredServers[info.serverId] = info; + } + } +} diff --git a/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta new file mode 100644 index 0000000..c56f65f --- /dev/null +++ b/Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 88c37d3deca7a834d80cfd8d3cfcc510 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Discovery/NetworkDiscoveryHUD.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs b/Assets/Mirror/Components/Discovery/ServerRequest.cs new file mode 100644 index 0000000..647b619 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerRequest.cs @@ -0,0 +1,4 @@ +namespace Mirror.Discovery +{ + public struct ServerRequest : NetworkMessage {} +} diff --git a/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta new file mode 100644 index 0000000..84d4d68 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerRequest.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ea7254bf7b9454da4adad881d94cd141 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Discovery/ServerRequest.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs b/Assets/Mirror/Components/Discovery/ServerResponse.cs new file mode 100644 index 0000000..7465783 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Net; + +namespace Mirror.Discovery +{ + public struct ServerResponse : NetworkMessage + { + // The server that sent this + // this is a property so that it is not serialized, but the + // client fills this up after we receive it + public IPEndPoint EndPoint { get; set; } + + public Uri uri; + + // Prevent duplicate server appearance when a connection can be made via LAN on multiple NICs + public long serverId; + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta new file mode 100644 index 0000000..3ca8f78 --- /dev/null +++ b/Assets/Mirror/Components/Discovery/ServerResponse.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 36f97227fdf2d7a4e902db5bfc43039c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Discovery/ServerResponse.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/GUIConsole.cs b/Assets/Mirror/Components/GUIConsole.cs new file mode 100644 index 0000000..7055fe1 --- /dev/null +++ b/Assets/Mirror/Components/GUIConsole.cs @@ -0,0 +1,133 @@ +// People should be able to see and report errors to the developer very easily. +// +// Unity's Developer Console only works in development builds and it only shows +// errors. This class provides a console that works in all builds and also shows +// log and warnings in development builds. +// +// Note: we don't include the stack trace, because that can also be grabbed from +// the log files if needed. +// +// Note: there is no 'hide' button because we DO want people to see those errors +// and report them back to us. +// +// Note: normal Debug.Log messages can be shown by building in Debug/Development +// mode. +using UnityEngine; +using System.Collections.Generic; + +namespace Mirror +{ + struct LogEntry + { + public string message; + public LogType type; + + public LogEntry(string message, LogType type) + { + this.message = message; + this.type = type; + } + } + + public class GUIConsole : MonoBehaviour + { + public int height = 80; + public int offsetY = 40; + + // only keep the recent 'n' entries. otherwise memory would grow forever + // and drawing would get slower and slower. + public int maxLogCount = 50; + + // Unity Editor has the Console window, we don't need to show it there. + // unless for testing, so keep it as option. + public bool showInEditor = false; + + // log as queue so we can remove the first entry easily + readonly Queue log = new Queue(); + + // hotkey to show/hide at runtime for easier debugging + // (sometimes we need to temporarily hide/show it) + // Default is BackQuote, because F keys are already assigned in browsers + [Tooltip("Hotkey to show/hide the console at runtime\nBack Quote is usually on the left above Tab\nChange with caution - F keys are generally already taken in Browsers")] + public KeyCode hotKey = KeyCode.BackQuote; + + // GUI + bool visible; + Vector2 scroll = Vector2.zero; + + // only show at runtime, or if showInEditor is enabled + bool show => !Application.isEditor || showInEditor; + + void Awake() + { + // only show at runtime, or if showInEditor is enabled + if (show) + Application.logMessageReceived += OnLog; + } + + // OnLog logs everything, even Debug.Log messages in release builds + // => this makes a lot of things easier. e.g. addon initialization logs. + // => it's really better to have than not to have those + void OnLog(string message, string stackTrace, LogType type) + { + // is this important? + // => always show exceptions & errors + // => usually a good idea to show warnings too, otherwise it's too + // easy to miss OnDeserialize warnings etc. in builds + bool isImportant = type == LogType.Error || type == LogType.Exception || type == LogType.Warning; + + // use stack trace only if important + // (otherwise users would have to find and search the log file. + // seeing it in the console directly is way easier to deal with.) + // => only add \n if stack trace is available (only in debug builds) + if (isImportant && !string.IsNullOrWhiteSpace(stackTrace)) + message += $"\n{stackTrace}"; + + // add to queue + log.Enqueue(new LogEntry(message, type)); + + // respect max entries + if (log.Count > maxLogCount) + log.Dequeue(); + + // become visible if it was important + // (no need to become visible for regular log. let the user decide.) + if (isImportant) + visible = true; + + // auto scroll + scroll.y = float.MaxValue; + } + + void Update() + { + if (show && Input.GetKeyDown(hotKey)) + visible = !visible; + } + + void OnGUI() + { + if (!visible) return; + + // If this offset is changed, also change width in NetworkManagerHUD::OnGUI + int offsetX = 300 + 20; + + GUILayout.BeginArea(new Rect(offsetX, offsetY, Screen.width - offsetX - 10, height)); + + scroll = GUILayout.BeginScrollView(scroll, "Box", GUILayout.Width(Screen.width - offsetX - 10), GUILayout.Height(height)); + foreach (LogEntry entry in log) + { + if (entry.type == LogType.Error || entry.type == LogType.Exception) + GUI.color = Color.red; + else if (entry.type == LogType.Warning) + GUI.color = Color.yellow; + + GUILayout.Label(entry.message); + GUI.color = Color.white; + } + GUILayout.EndScrollView(); + + GUILayout.EndArea(); + } + } +} diff --git a/Assets/Mirror/Components/GUIConsole.cs.meta b/Assets/Mirror/Components/GUIConsole.cs.meta new file mode 100644 index 0000000..283ae43 --- /dev/null +++ b/Assets/Mirror/Components/GUIConsole.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9021b6cc314944290986ab6feb48db79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/GUIConsole.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement.meta b/Assets/Mirror/Components/InterestManagement.meta new file mode 100644 index 0000000..9b1f746 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c66f27e006ab94253b39a55a3b213651 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/InterestManagement/Distance.meta b/Assets/Mirror/Components/InterestManagement/Distance.meta new file mode 100644 index 0000000..832357e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa4cbc6b9c584db4971985cb9f369077 +timeCreated: 1613110605 diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs new file mode 100644 index 0000000..e4f56ca --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs @@ -0,0 +1,89 @@ +// straight forward Vector3.Distance based interest management. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Distance/Distance Interest Management")] + public class DistanceInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at. Add DistanceInterestManagementCustomRange onto NetworkIdentities for custom ranges.")] + public int visRange = 500; + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + // cache custom ranges to avoid runtime TryGetComponent lookups + readonly Dictionary CustomRanges = new Dictionary(); + + // helper function to get vis range for a given object, or default. + [ServerCallback] + int GetVisRange(NetworkIdentity identity) + { + return CustomRanges.TryGetValue(identity, out DistanceInterestManagementCustomRange custom) ? custom.visRange : visRange; + } + + [ServerCallback] + public override void ResetState() + { + lastRebuildTime = 0D; + CustomRanges.Clear(); + } + + public override void OnSpawned(NetworkIdentity identity) + { + if (identity.TryGetComponent(out DistanceInterestManagementCustomRange custom)) + CustomRanges[identity] = custom; + } + + public override void OnDestroyed(NetworkIdentity identity) + { + CustomRanges.Remove(identity); + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + int range = GetVisRange(identity); + return Vector3.Distance(identity.transform.position, newObserver.identity.transform.position) < range; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // cache range and .transform because both call GetComponent. + int range = GetVisRange(identity); + Vector3 position = identity.transform.position; + + // brute force distance check + // -> only player connections can be observers, so it's enough if we + // go through all connections instead of all spawned identities. + // -> compared to UNET's sphere cast checking, this one is orders of + // magnitude faster. if we have 10k monsters and run a sphere + // cast 10k times, we will see a noticeable lag even with physics + // layers. but checking to every connection is fast. + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (conn != null && conn.isAuthenticated && conn.identity != null) + { + // check distance + if (Vector3.Distance(conn.identity.transform.position, position) < range) + { + newObservers.Add(conn); + } + } + } + } + + [ServerCallback] + void LateUpdate() + { + // rebuild all spawned NetworkIdentity's observers every interval + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta new file mode 100644 index 0000000..b0e89d9 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8f60becab051427fbdd3c8ac9ab4712b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs new file mode 100644 index 0000000..12556e5 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs @@ -0,0 +1,15 @@ +// add this to NetworkIdentities for custom range if needed. +// only works with DistanceInterestManagement. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Interest Management/ Distance/Distance Custom Range")] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public class DistanceInterestManagementCustomRange : NetworkBehaviour + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 100; + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta new file mode 100644 index 0000000..369f702 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b2e242ee38a14076a39934172a19079b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Distance/DistanceInterestManagementCustomRange.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Match.meta b/Assets/Mirror/Components/InterestManagement/Match.meta new file mode 100644 index 0000000..2cfaabc --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5eca5245ae6bb460e9a92f7e14d5493a +timeCreated: 1622649517 diff --git a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs new file mode 100644 index 0000000..d741d0c --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Match/Match Interest Management")] + public class MatchInterestManagement : InterestManagement + { + [Header("Diagnostics")] + [ReadOnly, SerializeField] + internal ushort matchCount; + + readonly Dictionary> matchObjects = + new Dictionary>(); + + readonly HashSet dirtyMatches = new HashSet(); + + // LateUpdate so that all spawns/despawns/changes are done + [ServerCallback] + void LateUpdate() + { + // Rebuild all dirty matches + // dirtyMatches will be empty if no matches changed members + // by spawning or destroying or changing matchId in this frame. + foreach (Guid dirtyMatch in dirtyMatches) + { + // rebuild always, even if matchObjects[dirtyMatch] is empty. + // Players might have left the match, but they may still be spawned. + RebuildMatchObservers(dirtyMatch); + + // clean up empty entries in the dict + if (matchObjects[dirtyMatch].Count == 0) + matchObjects.Remove(dirtyMatch); + } + + dirtyMatches.Clear(); + + matchCount = (ushort)matchObjects.Count; + } + + [ServerCallback] + void RebuildMatchObservers(Guid matchId) + { + foreach (NetworkMatch networkMatch in matchObjects[matchId]) + if (networkMatch.netIdentity != null) + NetworkServer.RebuildObservers(networkMatch.netIdentity, false); + } + + // called by NetworkMatch.matchId setter + [ServerCallback] + internal void OnMatchChanged(NetworkMatch networkMatch, Guid oldMatch) + { + // This object is in a new match so observers in the prior match + // and the new match need to rebuild their respective observers lists. + + // Remove this object from the hashset of the match it just left + // Guid.Empty is never a valid matchId + if (oldMatch != Guid.Empty) + { + dirtyMatches.Add(oldMatch); + matchObjects[oldMatch].Remove(networkMatch); + } + + // Guid.Empty is never a valid matchId + if (networkMatch.matchId == Guid.Empty) + return; + + dirtyMatches.Add(networkMatch.matchId); + + // Make sure this new match is in the dictionary + if (!matchObjects.ContainsKey(networkMatch.matchId)) + matchObjects[networkMatch.matchId] = new HashSet(); + + // Add this object to the hashset of the new match + matchObjects[networkMatch.matchId].Add(networkMatch); + } + + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) + { + if (!identity.TryGetComponent(out NetworkMatch networkMatch)) + return; + + Guid networkMatchId = networkMatch.matchId; + + // Guid.Empty is never a valid matchId...do not add to matchObjects collection + if (networkMatchId == Guid.Empty) + return; + + // Debug.Log($"MatchInterestManagement.OnSpawned({identity.name}) currentMatch: {currentMatch}"); + if (!matchObjects.TryGetValue(networkMatchId, out HashSet objects)) + { + objects = new HashSet(); + matchObjects.Add(networkMatchId, objects); + } + + objects.Add(networkMatch); + + // Match ID could have been set in NetworkBehaviour::OnStartServer on this object. + // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. + // Add the current match to dirtyMatches for LateUpdate to rebuild it. + dirtyMatches.Add(networkMatchId); + } + + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) + { + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current match to dirtyMatches for LateUpdate to rebuild it. + if (identity.TryGetComponent(out NetworkMatch currentMatch)) + { + if (currentMatch.matchId != Guid.Empty && + matchObjects.TryGetValue(currentMatch.matchId, out HashSet objects) && + objects.Remove(currentMatch)) + dirtyMatches.Add(currentMatch.matchId); + } + } + + [ServerCallback] + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // Never observed if no NetworkMatch component + if (!identity.TryGetComponent(out NetworkMatch identityNetworkMatch)) + return false; + + // Guid.Empty is never a valid matchId + if (identityNetworkMatch.matchId == Guid.Empty) + return false; + + // Never observed if no NetworkMatch component + if (!newObserver.identity.TryGetComponent(out NetworkMatch newObserverNetworkMatch)) + return false; + + // Guid.Empty is never a valid matchId + if (newObserverNetworkMatch.matchId == Guid.Empty) + return false; + + return identityNetworkMatch.matchId == newObserverNetworkMatch.matchId; + } + + [ServerCallback] + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + if (!identity.TryGetComponent(out NetworkMatch networkMatch)) + return; + + // Guid.Empty is never a valid matchId + if (networkMatch.matchId == Guid.Empty) + return; + + // Abort if this match hasn't been created yet by OnSpawned or OnMatchChanged + if (!matchObjects.TryGetValue(networkMatch.matchId, out HashSet objects)) + return; + + // Add everything in the hashset for this object's current match + foreach (NetworkMatch netMatch in objects) + if (netMatch.netIdentity != null && netMatch.netIdentity.connectionToClient != null) + newObservers.Add(netMatch.netIdentity.connectionToClient); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta new file mode 100644 index 0000000..bc4b6da --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d09f5c8bf2f4747b7a9284ef5d9ce2a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Match/MatchInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs new file mode 100644 index 0000000..0d55fd0 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs @@ -0,0 +1,42 @@ +// simple component that holds match information +using System; +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Interest Management/ Match/Network Match")] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public class NetworkMatch : NetworkBehaviour + { + Guid _matchId; + +#pragma warning disable IDE0052 // Suppress warning for unused field...this is for debugging purposes + [SerializeField, ReadOnly] + [Tooltip("Match ID is shown here on server for debugging purposes.")] + string MatchID = string.Empty; +#pragma warning restore IDE0052 + + ///Set this to the same value on all networked objects that belong to a given match + public Guid matchId + { + get => _matchId; + set + { + if (!NetworkServer.active) + throw new InvalidOperationException("matchId can only be set at runtime on active server"); + + if (_matchId == value) + return; + + Guid oldMatch = _matchId; + _matchId = value; + MatchID = value.ToString(); + + // Only inform the AOI if this netIdentity has been spawned (isServer) and only if using a MatchInterestManagement + if (isServer && NetworkServer.aoi is MatchInterestManagement matchInterestManagement) + matchInterestManagement.OnMatchChanged(this, oldMatch); + } + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs.meta b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs.meta new file mode 100644 index 0000000..a7158ac --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5d17e718851449a6879986e45c458fb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Match/NetworkMatch.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Scene.meta b/Assets/Mirror/Components/InterestManagement/Scene.meta new file mode 100644 index 0000000..f1fa700 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7655d309a46a4bd4860edf964228b3f6 +timeCreated: 1622649517 diff --git a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs new file mode 100644 index 0000000..c688dfd --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs @@ -0,0 +1,117 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Scene/Scene Interest Management")] + public class SceneInterestManagement : InterestManagement + { + // Use Scene instead of string scene.name because when additively + // loading multiples of a subscene the name won't be unique + readonly Dictionary> sceneObjects = + new Dictionary>(); + + readonly Dictionary lastObjectScene = + new Dictionary(); + + HashSet dirtyScenes = new HashSet(); + + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) + { + Scene currentScene = identity.gameObject.scene; + lastObjectScene[identity] = currentScene; + // Debug.Log($"SceneInterestManagement.OnSpawned({identity.name}) currentScene: {currentScene}"); + if (!sceneObjects.TryGetValue(currentScene, out HashSet objects)) + { + objects = new HashSet(); + sceneObjects.Add(currentScene, objects); + } + + objects.Add(identity); + } + + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) + { + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current scene to dirtyScenes for LateUpdate to rebuild it. + if (lastObjectScene.TryGetValue(identity, out Scene currentScene)) + { + lastObjectScene.Remove(identity); + if (sceneObjects.TryGetValue(currentScene, out HashSet objects) && objects.Remove(identity)) + dirtyScenes.Add(currentScene); + } + } + + [ServerCallback] + void LateUpdate() + { + // for each spawned: + // if scene changed: + // add previous to dirty + // add new to dirty + foreach (NetworkIdentity identity in NetworkServer.spawned.Values) + { + if (!lastObjectScene.TryGetValue(identity, out Scene currentScene)) + continue; + + Scene newScene = identity.gameObject.scene; + if (newScene == currentScene) + continue; + + // Mark new/old scenes as dirty so they get rebuilt + dirtyScenes.Add(currentScene); + dirtyScenes.Add(newScene); + + // This object is in a new scene so observers in the prior scene + // and the new scene need to rebuild their respective observers lists. + + // Remove this object from the hashset of the scene it just left + sceneObjects[currentScene].Remove(identity); + + // Set this to the new scene this object just entered + lastObjectScene[identity] = newScene; + + // Make sure this new scene is in the dictionary + if (!sceneObjects.ContainsKey(newScene)) + sceneObjects.Add(newScene, new HashSet()); + + // Add this object to the hashset of the new scene + sceneObjects[newScene].Add(identity); + } + + // rebuild all dirty scenes + foreach (Scene dirtyScene in dirtyScenes) + RebuildSceneObservers(dirtyScene); + + dirtyScenes.Clear(); + } + + void RebuildSceneObservers(Scene scene) + { + foreach (NetworkIdentity netIdentity in sceneObjects[scene]) + if (netIdentity != null) + NetworkServer.RebuildObservers(netIdentity, false); + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + return identity.gameObject.scene == newObserver.identity.gameObject.scene; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + if (!sceneObjects.TryGetValue(identity.gameObject.scene, out HashSet objects)) + return; + + // Add everything in the hashset for this object's current scene + foreach (NetworkIdentity networkIdentity in objects) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + newObservers.Add(networkIdentity.connectionToClient); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta new file mode 100644 index 0000000..99925b0 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b979f26c95d34324ba005bfacfa9c4fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Scene/SceneInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SceneDistance.meta b/Assets/Mirror/Components/InterestManagement/SceneDistance.meta new file mode 100644 index 0000000..f010228 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SceneDistance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4d8c634a8103664db5f90fe8bab9544 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs new file mode 100644 index 0000000..cdd5f16 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs @@ -0,0 +1,178 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Scene/Scene Distance Interest Management")] + public class SceneDistanceInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at. Add DistanceInterestManagementCustomRange onto NetworkIdentities for custom ranges.")] + public int visRange = 500; + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + // cache custom ranges to avoid runtime TryGetComponent lookups + readonly Dictionary CustomRanges = new Dictionary(); + + // helper function to get vis range for a given object, or default. + [ServerCallback] + int GetVisRange(NetworkIdentity identity) + { + return CustomRanges.TryGetValue(identity, out DistanceInterestManagementCustomRange custom) ? custom.visRange : visRange; + } + + [ServerCallback] + public override void ResetState() + { + lastRebuildTime = 0D; + CustomRanges.Clear(); + } + + // Use Scene instead of string scene.name because when additively + // loading multiples of a subscene the name won't be unique + readonly Dictionary> sceneObjects = + new Dictionary>(); + + readonly Dictionary lastObjectScene = + new Dictionary(); + + HashSet dirtyScenes = new HashSet(); + + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) + { + if (identity.TryGetComponent(out DistanceInterestManagementCustomRange custom)) + CustomRanges[identity] = custom; + + Scene currentScene = identity.gameObject.scene; + lastObjectScene[identity] = currentScene; + // Debug.Log($"SceneInterestManagement.OnSpawned({identity.name}) currentScene: {currentScene}"); + if (!sceneObjects.TryGetValue(currentScene, out HashSet objects)) + { + objects = new HashSet(); + sceneObjects.Add(currentScene, objects); + } + + objects.Add(identity); + } + + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) + { + CustomRanges.Remove(identity); + + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current scene to dirtyScenes for LateUpdate to rebuild it. + if (lastObjectScene.TryGetValue(identity, out Scene currentScene)) + { + lastObjectScene.Remove(identity); + if (sceneObjects.TryGetValue(currentScene, out HashSet objects) && objects.Remove(identity)) + dirtyScenes.Add(currentScene); + } + } + + [ServerCallback] + void LateUpdate() + { + // for each spawned: + // if scene changed: + // add previous to dirty + // add new to dirty + // else + // if rebuild interval reached: + // rebuild all + foreach (NetworkIdentity identity in NetworkServer.spawned.Values) + { + if (!lastObjectScene.TryGetValue(identity, out Scene currentScene)) + continue; + + Scene newScene = identity.gameObject.scene; + if (newScene == currentScene) + { + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + + // no scene change, so we're done here + continue; + } + + // Mark new/old scenes as dirty so they get rebuilt + dirtyScenes.Add(currentScene); + dirtyScenes.Add(newScene); + + // This object is in a new scene so observers in the prior scene + // and the new scene need to rebuild their respective observers lists. + + // Remove this object from the hashset of the scene it just left + sceneObjects[currentScene].Remove(identity); + + // Set this to the new scene this object just entered + lastObjectScene[identity] = newScene; + + // Make sure this new scene is in the dictionary + if (!sceneObjects.ContainsKey(newScene)) + sceneObjects.Add(newScene, new HashSet()); + + // Add this object to the hashset of the new scene + sceneObjects[newScene].Add(identity); + } + + // rebuild all dirty scenes + foreach (Scene dirtyScene in dirtyScenes) + RebuildSceneObservers(dirtyScene); + + dirtyScenes.Clear(); + } + + void RebuildSceneObservers(Scene scene) + { + foreach (NetworkIdentity netIdentity in sceneObjects[scene]) + if (netIdentity != null) + NetworkServer.RebuildObservers(netIdentity, false); + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // Check for scene match first, then distance + if (identity.gameObject.scene != newObserver.identity.gameObject.scene) return false; + + int range = GetVisRange(identity); + return Vector3.Distance(identity.transform.position, newObserver.identity.transform.position) < range; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // abort if no entry in sceneObjects yet (created in OnSpawned) + if (!sceneObjects.TryGetValue(identity.gameObject.scene, out HashSet objects)) + return; + + int range = GetVisRange(identity); + Vector3 position = identity.transform.position; + + // Add everything in the hashset for this object's current scene if within range + foreach (NetworkIdentity networkIdentity in objects) + if (networkIdentity != null && networkIdentity.connectionToClient != null) + { + // brute force distance check + // -> only player connections can be observers, so it's enough if we + // go through all connections instead of all spawned identities. + // -> compared to UNET's sphere cast checking, this one is orders of + // magnitude faster. if we have 10k monsters and run a sphere + // cast 10k times, we will see a noticeable lag even with physics + // layers. but checking to every connection is fast. + NetworkConnectionToClient conn = networkIdentity.connectionToClient; + if (conn != null && conn.isAuthenticated && conn.identity != null) + if (Vector3.Distance(conn.identity.transform.position, position) < range) + newObservers.Add(conn); + } + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs.meta new file mode 100644 index 0000000..3f74f73 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6471bc9a8f893944783fd54e9bfb6ed2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SceneDistance/SceneDistanceInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta new file mode 100644 index 0000000..6a35e1e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cfa12b73503344d49b398b01bcb07967 +timeCreated: 1613110634 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs new file mode 100644 index 0000000..d557713 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs @@ -0,0 +1,104 @@ +// Grid2D from uMMORPG: get/set values of type T at any point +// -> not named 'Grid' because Unity already has a Grid type. causes warnings. +// -> struct to avoid memory indirection. it's accessed a lot. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // struct to avoid memory indirection. it's accessed a lot. + public struct Grid2D + { + // the grid + // note that we never remove old keys. + // => over time, HashSets will be allocated for every possible + // grid position in the world + // => Clear() doesn't clear them so we don't constantly reallocate the + // entries when populating the grid in every Update() call + // => makes the code a lot easier too + // => this is FINE because in the worst case, every grid position in the + // game world is filled with a player anyway! + readonly Dictionary> grid; + + // cache a 9 neighbor grid of vector2 offsets so we can use them more easily + readonly Vector2Int[] neighbourOffsets; + + public Grid2D(int initialCapacity) + { + grid = new Dictionary>(initialCapacity); + + neighbourOffsets = new[] { + Vector2Int.up, + Vector2Int.up + Vector2Int.left, + Vector2Int.up + Vector2Int.right, + Vector2Int.left, + Vector2Int.zero, + Vector2Int.right, + Vector2Int.down, + Vector2Int.down + Vector2Int.left, + Vector2Int.down + Vector2Int.right + }; + } + + // helper function so we can add an entry without worrying + public void Add(Vector2Int position, T value) + { + // initialize set in grid if it's not in there yet + if (!grid.TryGetValue(position, out HashSet hashSet)) + { + // each grid entry may hold hundreds of entities. + // let's create the HashSet with a large initial capacity + // in order to avoid resizing & allocations. +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have "new HashSet(capacity)" yet + hashSet = new HashSet(); +#else + hashSet = new HashSet(128); +#endif + grid[position] = hashSet; + } + + // add to it + hashSet.Add(value); + } + + // helper function to get set at position without worrying + // -> result is passed as parameter to avoid allocations + // -> result is not cleared before. this allows us to pass the HashSet from + // GetWithNeighbours and avoid .UnionWith which is very expensive. + void GetAt(Vector2Int position, HashSet result) + { + // return the set at position + if (grid.TryGetValue(position, out HashSet hashSet)) + { + foreach (T entry in hashSet) + result.Add(entry); + } + } + + // helper function to get at position and it's 8 neighbors without worrying + // -> result is passed as parameter to avoid allocations + public void GetWithNeighbours(Vector2Int position, HashSet result) + { + // clear result first + result.Clear(); + + // add neighbours + foreach (Vector2Int offset in neighbourOffsets) + GetAt(position + offset, result); + } + + // clear: clears the whole grid + // IMPORTANT: we already allocated HashSets and don't want to do + // reallocate every single update when we rebuild the grid. + // => so simply remove each position's entries, but keep + // every position in there + // => see 'grid' comments above! + // => named ClearNonAlloc to make it more obvious! + public void ClearNonAlloc() + { + foreach (HashSet hashSet in grid.Values) + hashSet.Clear(); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta new file mode 100644 index 0000000..b8dd422 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7c5232a4d2854116a35d52b80ec07752 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid2D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs new file mode 100644 index 0000000..64ca497 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs @@ -0,0 +1,106 @@ +// Grid3D based on Grid2D +// -> not named 'Grid' because Unity already has a Grid type. causes warnings. +// -> struct to avoid memory indirection. it's accessed a lot. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // struct to avoid memory indirection. it's accessed a lot. + public struct Grid3D + { + // the grid + // note that we never remove old keys. + // => over time, HashSets will be allocated for every possible + // grid position in the world + // => Clear() doesn't clear them so we don't constantly reallocate the + // entries when populating the grid in every Update() call + // => makes the code a lot easier too + // => this is FINE because in the worst case, every grid position in the + // game world is filled with a player anyway! + readonly Dictionary> grid; + + // cache a 9 x 3 neighbor grid of vector3 offsets so we can use them more easily + readonly Vector3Int[] neighbourOffsets; + + public Grid3D(int initialCapacity) + { + grid = new Dictionary>(initialCapacity); + + neighbourOffsets = new Vector3Int[9 * 3]; + int i = 0; + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + for (int z = -1; z <= 1; z++) + { + neighbourOffsets[i] = new Vector3Int(x, y, z); + i += 1; + } + } + } + } + + // helper function so we can add an entry without worrying + public void Add(Vector3Int position, T value) + { + // initialize set in grid if it's not in there yet + if (!grid.TryGetValue(position, out HashSet hashSet)) + { + // each grid entry may hold hundreds of entities. + // let's create the HashSet with a large initial capacity + // in order to avoid resizing & allocations. +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have "new HashSet(capacity)" yet + hashSet = new HashSet(); +#else + hashSet = new HashSet(128); +#endif + grid[position] = hashSet; + } + + // add to it + hashSet.Add(value); + } + + // helper function to get set at position without worrying + // -> result is passed as parameter to avoid allocations + // -> result is not cleared before. this allows us to pass the HashSet from + // GetWithNeighbours and avoid .UnionWith which is very expensive. + void GetAt(Vector3Int position, HashSet result) + { + // return the set at position + if (grid.TryGetValue(position, out HashSet hashSet)) + { + foreach (T entry in hashSet) + result.Add(entry); + } + } + + // helper function to get at position and it's 8 neighbors without worrying + // -> result is passed as parameter to avoid allocations + public void GetWithNeighbours(Vector3Int position, HashSet result) + { + // clear result first + result.Clear(); + + // add neighbours + foreach (Vector3Int offset in neighbourOffsets) + GetAt(position + offset, result); + } + + // clear: clears the whole grid + // IMPORTANT: we already allocated HashSets and don't want to do + // reallocate every single update when we rebuild the grid. + // => so simply remove each position's entries, but keep + // every position in there + // => see 'grid' comments above! + // => named ClearNonAlloc to make it more obvious! + public void ClearNonAlloc() + { + foreach (HashSet hashSet in grid.Values) + hashSet.Clear(); + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta new file mode 100644 index 0000000..a3268e7 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b157c08313c64752b0856469b1b70771 +timeCreated: 1713533175 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/Grid3D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs new file mode 100644 index 0000000..29bd6ce --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs @@ -0,0 +1,170 @@ +using UnityEngine; + +namespace Mirror +{ + internal class HexGrid2D + { + // Radius of each hexagonal cell (half the width) + internal float cellRadius; + + // Offset applied to align the grid with the world origin + Vector2 originOffset; + + // Precomputed constants for hexagon math to improve performance + readonly float sqrt3Div3; // sqrt(3) / 3, used in coordinate conversions + readonly float oneDiv3; // 1 / 3, used in coordinate conversions + readonly float twoDiv3; // 2 / 3, used in coordinate conversions + readonly float sqrt3; // sqrt(3), used in world coordinate calculations + readonly float sqrt3Div2; // sqrt(3) / 2, used in world coordinate calculations + + internal HexGrid2D(ushort visRange) + { + // Set cell radius as half the visibility range + cellRadius = visRange / 2f; + + // Offset to center the grid at world origin (2D XZ plane) + originOffset = Vector2.zero; + + // Precompute mathematical constants for efficiency + sqrt3Div3 = Mathf.Sqrt(3) / 3f; + oneDiv3 = 1f / 3f; + twoDiv3 = 2f / 3f; + sqrt3 = Mathf.Sqrt(3); + sqrt3Div2 = Mathf.Sqrt(3) / 2f; + } + + // Precomputed array of neighbor offsets as Cell2D structs (center + 6 neighbors) + static readonly Cell2D[] neighborCellsBase = new Cell2D[] + { + new Cell2D(0, 0), // Center + new Cell2D(1, -1), // Top-right + new Cell2D(1, 0), // Right + new Cell2D(0, 1), // Bottom-right + new Cell2D(-1, 1), // Bottom-left + new Cell2D(-1, 0), // Left + new Cell2D(0, -1) // Top-left + }; + + // Converts a grid cell (q, r) to a world position (x, z) + internal Vector2 CellToWorld(Cell2D cell) + { + // Calculate X and Z using hexagonal coordinate formulas + float x = cellRadius * (sqrt3 * cell.q + sqrt3Div2 * cell.r); + float z = cellRadius * (1.5f * cell.r); + + // Subtract the origin offset to align with world space and return the position + return new Vector2(x, z) - originOffset; + } + + // Converts a world position (x, z) to a grid cell (q, r) + internal Cell2D WorldToCell(Vector2 position) + { + // Apply the origin offset to adjust the position before conversion + position += originOffset; + + // Convert world X, Z to axial q, r coordinates using inverse hexagonal formulas + float q = (sqrt3Div3 * position.x - oneDiv3 * position.y) / cellRadius; + float r = (twoDiv3 * position.y) / cellRadius; + + // Round to the nearest valid cell and return + return RoundToCell(q, r); + } + + // Rounds floating-point axial coordinates (q, r) to the nearest integer cell coordinates + Cell2D RoundToCell(float q, float r) + { + // Calculate the third hexagonal coordinate (s) for consistency + float s = -q - r; + int qInt = Mathf.RoundToInt(q); // Round q to nearest integer + int rInt = Mathf.RoundToInt(r); // Round r to nearest integer + int sInt = Mathf.RoundToInt(s); // Round s to nearest integer + + // Calculate differences to determine which coordinate needs adjustment + float qDiff = Mathf.Abs(q - qInt); + float rDiff = Mathf.Abs(r - rInt); + float sDiff = Mathf.Abs(s - sInt); + + // Adjust q or r based on which has the largest rounding error (ensures q + r + s = 0) + if (qDiff > rDiff && qDiff > sDiff) + qInt = -rInt - sInt; // Adjust q if it has the largest error + else if (rDiff > sDiff) + rInt = -qInt - sInt; // Adjust r if it has the largest error + + return new Cell2D(qInt, rInt); + } + + // Populates the provided array with neighboring cells around a given center cell + internal void GetNeighborCells(Cell2D center, Cell2D[] neighbors) + { + // Ensure the array has the correct size (7: center + 6 neighbors) + if (neighbors.Length != 7) + throw new System.ArgumentException("Neighbor array must have exactly 7 elements"); + + // Populate the array by adjusting precomputed offsets with the center cell's coordinates + for (int i = 0; i < neighborCellsBase.Length; i++) + { + neighbors[i] = new Cell2D( + center.q + neighborCellsBase[i].q, + center.r + neighborCellsBase[i].r + ); + } + } + +#if UNITY_EDITOR + // Draws a 2D hexagonal gizmo in the Unity Editor for visualization + internal void DrawHexGizmo(Vector3 center, float radius, HexSpatialHash2DInterestManagement.CheckMethod checkMethod) + { + // Hexagon has 6 sides + const int segments = 6; + + // Array to store the 6 corner points in 3D + Vector3[] corners = new Vector3[segments]; + + // Calculate the corner positions based on the plane (XZ or XY) + for (int i = 0; i < segments; i++) + { + // Angle for each corner, offset by 90 degrees + float angle = 2 * Mathf.PI / segments * i + Mathf.PI / 2; + + if (checkMethod == HexSpatialHash2DInterestManagement.CheckMethod.XZ_FOR_3D) + { + // XZ plane: flat hexagon, Y=0 + corners[i] = center + new Vector3(radius * Mathf.Cos(angle), 0, radius * Mathf.Sin(angle)); + } + else // XY_FOR_2D + { + // XY plane: vertical hexagon, Z=0 + corners[i] = center + new Vector3(radius * Mathf.Cos(angle), radius * Mathf.Sin(angle), 0); + } + } + + // Draw each side of the hexagon + for (int i = 0; i < segments; i++) + { + Vector3 cornerA = corners[i]; + Vector3 cornerB = corners[(i + 1) % segments]; + Gizmos.DrawLine(cornerA, cornerB); + } + } +#endif + } + + // Struct representing a single cell in the 2D hexagonal grid + internal struct Cell2D + { + internal readonly int q; // Axial q coordinate (horizontal axis) + internal readonly int r; // Axial r coordinate (diagonal axis) + + internal Cell2D(int q, int r) + { + this.q = q; + this.r = r; + } + + public override bool Equals(object obj) => + obj is Cell2D other && q == other.q && r == other.r; + + // Generate a unique hash code for the cell + public override int GetHashCode() => (q << 16) ^ r; + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs.meta new file mode 100644 index 0000000..83542fb --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e9b8dc0273250624c91b6681065741ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid2D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs new file mode 100644 index 0000000..b7a0fd3 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs @@ -0,0 +1,243 @@ +using UnityEngine; + +namespace Mirror +{ + internal class HexGrid3D + { + // Radius of each hexagonal cell (half the width) + internal float cellRadius; + + // Height of each cell along the Y-axis + internal float cellHeight; + + // Offset applied to align the grid with the world origin + Vector3 originOffset; + + // Precomputed constants for hexagon math to improve performance + readonly float sqrt3Div3; // sqrt(3) / 3, used in coordinate conversions + readonly float oneDiv3; // 1 / 3, used in coordinate conversions + readonly float twoDiv3; // 2 / 3, used in coordinate conversions + readonly float sqrt3; // sqrt(3), used in world coordinate calculations + readonly float sqrt3Div2; // sqrt(3) / 2, used in world coordinate calculations + + internal HexGrid3D(ushort visRange, ushort height) + { + // Set cell radius as half the visibility range + cellRadius = visRange / 2f; + + // Cell3D height is absolute...don't double it + cellHeight = height; + + // Offset to center the grid at world origin + // Cell3D height must be divided by 2 for vertical centering + originOffset = new Vector3(0, -cellHeight / 2, 0); + + // Precompute mathematical constants for efficiency + sqrt3Div3 = Mathf.Sqrt(3) / 3f; + oneDiv3 = 1f / 3f; + twoDiv3 = 2f / 3f; + sqrt3 = Mathf.Sqrt(3); + sqrt3Div2 = Mathf.Sqrt(3) / 2f; + } + + // Precomputed array of neighbor offsets as Cell3D structs (center + 6 per layer x 3 layers) + static readonly Cell3D[] neighborCellsBase = new Cell3D[] + { + // Center + new Cell3D(0, 0, 0), + // Upper layer (1) and its 6 neighbors + new Cell3D(0, 0, 1), + new Cell3D(1, -1, 1), new Cell3D(1, 0, 1), new Cell3D(0, 1, 1), + new Cell3D(-1, 1, 1), new Cell3D(-1, 0, 1), new Cell3D(0, -1, 1), + // Same layer (0) - 6 neighbors + new Cell3D(1, -1, 0), new Cell3D(1, 0, 0), new Cell3D(0, 1, 0), + new Cell3D(-1, 1, 0), new Cell3D(-1, 0, 0), new Cell3D(0, -1, 0), + // Lower layer (-1) and its 6 neighbors + new Cell3D(0, 0, -1), + new Cell3D(1, -1, -1), new Cell3D(1, 0, -1), new Cell3D(0, 1, -1), + new Cell3D(-1, 1, -1), new Cell3D(-1, 0, -1), new Cell3D(0, -1, -1) + }; + + // Converts a grid cell (q, r, layer) to a world position (x, y, z) + internal Vector3 CellToWorld(Cell3D cell) + { + // Calculate X and Z using hexagonal coordinate formulas + float x = cellRadius * (sqrt3 * cell.q + sqrt3Div2 * cell.r); + float z = cellRadius * (1.5f * cell.r); + + // Calculate Y based on layer and cell height + float y = cell.layer * cellHeight + cellHeight / 2; + + // Subtract the origin offset to align with world space and return the position + return new Vector3(x, y, z) - originOffset; + } + + // Converts a world position (x, y, z) to a grid cell (q, r, layer) + internal Cell3D WorldToCell(Vector3 position) + { + // Apply the origin offset to adjust the position before conversion + position += originOffset; + + // Calculate the vertical layer based on Y position + int layer = Mathf.FloorToInt(position.y / cellHeight); + + // Convert world X, Z to axial q, r coordinates using inverse hexagonal formulas + float q = (sqrt3Div3 * position.x - oneDiv3 * position.z) / cellRadius; + float r = (twoDiv3 * position.z) / cellRadius; + + // Round to the nearest valid cell and return + return RoundToCell(q, r, layer); + } + + // Rounds floating-point axial coordinates (q, r) to the nearest integer cell coordinates + Cell3D RoundToCell(float q, float r, int layer) + { + // Calculate the third hexagonal coordinate (s) for consistency + float s = -q - r; + int qInt = Mathf.RoundToInt(q); // Round q to nearest integer + int rInt = Mathf.RoundToInt(r); // Round r to nearest integer + int sInt = Mathf.RoundToInt(s); // Round s to nearest integer + + // Calculate differences to determine which coordinate needs adjustment + float qDiff = Mathf.Abs(q - qInt); + float rDiff = Mathf.Abs(r - rInt); + float sDiff = Mathf.Abs(s - sInt); + + // Adjust q or r based on which has the largest rounding error (ensures q + r + s = 0) + if (qDiff > rDiff && qDiff > sDiff) + qInt = -rInt - sInt; // Adjust q if it has the largest error + else if (rDiff > sDiff) + rInt = -qInt - sInt; // Adjust r if it has the largest error + + return new Cell3D(qInt, rInt, layer); + } + + // Populates the provided array with neighboring cells around a given center cell + internal void GetNeighborCells(Cell3D center, Cell3D[] neighbors) + { + // Ensure the array has the correct size + if (neighbors.Length != 21) + throw new System.ArgumentException("Neighbor array must have exactly 21 elements"); + + // Populate the array by adjusting precomputed offsets with the center cell's coordinates + for (int i = 0; i < neighborCellsBase.Length; i++) + { + neighbors[i] = new Cell3D( + center.q + neighborCellsBase[i].q, + center.r + neighborCellsBase[i].r, + center.layer + neighborCellsBase[i].layer + ); + } + } + +#if UNITY_EDITOR + + // Draws a hexagonal gizmo in the Unity Editor for visualization + internal void DrawHexGizmo(Vector3 center, float radius, float height, int relativeLayer) + { + // Hexagon has 6 sides + const int segments = 6; + + // Array to store the 6 corner points + Vector3[] corners = new Vector3[segments]; + + // Calculate the corner positions of the hexagon in the XZ plane + for (int i = 0; i < segments; i++) + { + // Angle for each corner, offset by 90 degrees + float angle = 2 * Mathf.PI / segments * i + Mathf.PI / 2; + + // Calculate the corner position based on the angle and radius + corners[i] = center + new Vector3(radius * Mathf.Cos(angle), 0, radius * Mathf.Sin(angle)); + } + + // Set gizmo color based on the relative layer for easy identification + Color gizmoColor; + switch (relativeLayer) + { + case 1: + gizmoColor = Color.green; // Upper layer (positive Y) + break; + case 0: + gizmoColor = Color.cyan; // Same layer as the reference point + break; + case -1: + gizmoColor = Color.yellow; // Lower layer (negative Y) + break; + default: + gizmoColor = Color.red; // Fallback for unexpected layers + break; + } + + // Store the current Gizmos color to restore later + Color previousColor = Gizmos.color; + + // Apply the chosen color + Gizmos.color = gizmoColor; + + // Draw each side of the hexagon as a 3D quad (wall) + for (int i = 0; i < segments; i++) + { + // Current corner + Vector3 cornerA = corners[i]; + + // Next corner (wraps around at 6) + Vector3 cornerB = corners[(i + 1) % segments]; + + // Calculate top and bottom corners to form a vertical quad + Vector3 cornerATop = cornerA + Vector3.up * (height / 2); + Vector3 cornerBTop = cornerB + Vector3.up * (height / 2); + Vector3 cornerABottom = cornerA - Vector3.up * (height / 2); + Vector3 cornerBBottom = cornerB - Vector3.up * (height / 2); + + // Draw the four lines of the quad to visualize the wall + Gizmos.DrawLine(cornerATop, cornerBTop); + Gizmos.DrawLine(cornerBTop, cornerBBottom); + Gizmos.DrawLine(cornerBBottom, cornerABottom); + Gizmos.DrawLine(cornerABottom, cornerATop); + } + + // Restore the original Gizmos color + Gizmos.color = previousColor; + } + +#endif + } + + // Custom struct for neighbor offsets (reduced memory usage) + internal struct HexOffset + { + internal int qOffset; // Offset in the q (axial) coordinate + internal int rOffset; // Offset in the r (axial) coordinate + + internal HexOffset(int q, int r) + { + qOffset = q; + rOffset = r; + } + } + + // Struct representing a single cell in the 3D hexagonal grid + internal struct Cell3D + { + internal readonly int q; // Axial q coordinate (horizontal axis) + internal readonly int r; // Axial r coordinate (diagonal axis) + internal readonly int layer; // Vertical layer index (Y-axis stacking) + + internal Cell3D(int q, int r, int layer) + { + this.q = q; + this.r = r; + this.layer = layer; + } + + public override bool Equals(object obj) => + obj is Cell3D other + && q == other.q + && r == other.r + && layer == other.layer; + + // Generate a unique hash code for the cell + public override int GetHashCode() => (q << 16) ^ (r << 8) ^ layer; + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs.meta new file mode 100644 index 0000000..79a4425 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9c4fe05752c9a85458b8e44611fe832b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/HexGrid3D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs new file mode 100644 index 0000000..a394ce0 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs @@ -0,0 +1,345 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Spatial Hash/Hex Spatial Hash (2D)")] + public class HexSpatialHash2DInterestManagement : InterestManagement + { + [Range(1, 60), Tooltip("Time interval in seconds between observer rebuilds")] + public byte rebuildInterval = 1; + + [Range(1, 60), Tooltip("Time interval in seconds between static object rebuilds")] + public byte staticRebuildInterval = 10; + + [Range(10, 5000), Tooltip("Radius of super hex.\nSet to 10% larger than camera far clip plane.")] + public ushort visRange = 1100; + + [Range(1, 100), Tooltip("Distance an object must move for updating cell positions")] + public ushort minMoveDistance = 1; + + [Tooltip("Spatial Hashing supports XZ for 3D games or XY for 2D games.")] + public CheckMethod checkMethod = CheckMethod.XZ_FOR_3D; + + double lastRebuildTime; + + // Counter for batching static object updates + byte rebuildCounter = 0; + + HexGrid2D grid; + + // Sparse array mapping cell indices to sets of NetworkIdentities + readonly List> cells = new List>(); + + // Tracks the last known cell position and world position of each NetworkIdentity + readonly Dictionary lastIdentityPositions = new Dictionary(); + + // Tracks the last known cell position and world position of each player's connection (observer) + readonly Dictionary lastConnectionPositions = new Dictionary(); + + // Pre-allocated array for storing neighbor cells (center + 6 neighbors) + readonly Cell2D[] neighborCells = new Cell2D[7]; + + // Maps each connection to the set of NetworkIdentities it can observe, precomputed for rebuilds + readonly Dictionary> connectionObservers = new Dictionary>(); + + // Reusable list for safe iteration over NetworkIdentities, avoiding ToList() allocations + readonly List identityKeys = new List(); + + // Pool of reusable HashSet instances to reduce allocations + readonly Stack> cellPool = new Stack>(); + + // Set of static NetworkIdentities that don't move, updated less frequently + readonly HashSet staticObjects = new HashSet(); + + // Scene bounds: ±9 km (18 km total) in each dimension + const int MAX_Q = 19; // Covers -9 to 9 (~18 km) + const int MAX_R = 23; // Covers -11 to 11 (~18 km) + const ushort MAX_AREA = 9000; // Maximum area in meters + + public enum CheckMethod + { + XZ_FOR_3D, + XY_FOR_2D + } + + void Awake() + { + grid = new HexGrid2D(visRange); + // Initialize cells list with null entries up to max size (±9 km bounds) + int maxSize = MAX_Q * MAX_R; + for (int i = 0; i < maxSize; i++) + cells.Add(null); + } + + // Project 3D world position to 2D grid position based on checkMethod + Vector2 ProjectToGrid(Vector3 position) => + checkMethod == CheckMethod.XZ_FOR_3D + ? new Vector2(position.x, position.z) + : new Vector2(position.x, position.y); + + void LateUpdate() + { + if (NetworkTime.time - lastRebuildTime >= rebuildInterval) + { + // Update positions of all active connections (players) in the network + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + if (conn?.identity != null) // Ensure connection and its identity exist + { + Vector2 position = ProjectToGrid(conn.identity.transform.position); + // Only update if the position has changed significantly + if (!lastConnectionPositions.TryGetValue(conn, out (Cell2D cell, Vector2 worldPos) last) || + Vector2.Distance(position, last.worldPos) >= minMoveDistance) + { + Cell2D cell = grid.WorldToCell(position); // Convert world position to grid cell + lastConnectionPositions[conn] = (cell, position); // Store the player's cell and position + } + } + + // Populate the reusable list with current keys for safe iteration + identityKeys.Clear(); + identityKeys.AddRange(lastIdentityPositions.Keys); + + // Update dynamic objects every rebuild, static objects every staticRebuildInterval + bool updateStatic = rebuildCounter >= staticRebuildInterval; + foreach (NetworkIdentity identity in identityKeys) + if (updateStatic || !staticObjects.Contains(identity)) + UpdateIdentityPosition(identity); // Refresh cell position for dynamic or scheduled static objects + + if (updateStatic) + rebuildCounter = 0; // Reset the counter after updating static objects + else + rebuildCounter++; + + // Precompute observer sets for each connection before rebuilding + connectionObservers.Clear(); + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + if (conn?.identity == null || !lastConnectionPositions.TryGetValue(conn, out (Cell2D cell, Vector2 worldPos) connPos)) + continue; + + // Get cells visible from the player's position + grid.GetNeighborCells(connPos.cell, neighborCells); + + // Initialize the observer set for this connection + HashSet observers = new HashSet(); + connectionObservers[conn] = observers; + + // Add all identities in visible cells to the observer set + for (int i = 0; i < neighborCells.Length; i++) + { + int index = GetCellIndex(neighborCells[i]); + if (index >= 0 && index < cells.Count && cells[index] != null) + { + foreach (NetworkIdentity identity in cells[index]) + observers.Add(identity); + } + } + } + + // RebuildAll invokes NetworkServer.RebuildObservers on all spawned objects + base.RebuildAll(); + + // Update the last rebuild time + lastRebuildTime = NetworkTime.time; + } + } + + // Called when a new networked object is spawned on the server + public override void OnSpawned(NetworkIdentity identity) + { + // Register the new object's position in the grid system + UpdateIdentityPosition(identity); + + // Check if the object is statically batched (indicating it won't move) + Renderer[] renderers = identity.gameObject.GetComponentsInChildren(); + if (renderers.Any(r => r.isPartOfStaticBatch)) + staticObjects.Add(identity); + } + + // Updates the grid cell position of a NetworkIdentity when it moves or spawns + void UpdateIdentityPosition(NetworkIdentity identity) + { + // Get the current world position of the object + Vector2 position = ProjectToGrid(identity.transform.position); + + // Convert position to grid cell coordinates + Cell2D newCell = grid.WorldToCell(position); + + // Check if the object is within ±9 km bounds + if (Mathf.Abs(position.x) > MAX_AREA || Mathf.Abs(position.y) > MAX_AREA) + return; // Ignore objects outside bounds + + // Check if the object was previously tracked + if (lastIdentityPositions.TryGetValue(identity, out (Cell2D cell, Vector2 worldPos) previous)) + { + // Only update if the position has changed significantly or the cell has changed + if (Vector2.Distance(position, previous.worldPos) >= minMoveDistance || !newCell.Equals(previous.cell)) + { + if (!newCell.Equals(previous.cell)) + { + // Object moved to a new cell + // Remove it from the old cell's set and add it to the new cell's set + int oldIndex = GetCellIndex(previous.cell); + if (oldIndex >= 0 && oldIndex < cells.Count && cells[oldIndex] != null) + cells[oldIndex].Remove(identity); + AddToCell(newCell, identity); + } + // Update the stored position and cell + lastIdentityPositions[identity] = (newCell, position); + } + } + else + { + // New object - add it to the grid and track its position + AddToCell(newCell, identity); + lastIdentityPositions[identity] = (newCell, position); + } + } + + // Adds a NetworkIdentity to a specific cell's set of objects + void AddToCell(Cell2D cell, NetworkIdentity identity) + { + int index = GetCellIndex(cell); + if (index < 0 || index >= cells.Count) + return; // Out of bounds, ignore + + // If the cell doesn't exist in the array yet, fetch or create a new set from the pool + if (cells[index] == null) + { + cells[index] = cellPool.Count > 0 ? cellPool.Pop() : new HashSet(); + } + cells[index].Add(identity); + } + + // Determines if a new observer can see a given NetworkIdentity + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // Check if we have position data for both the object and the observer + if (!lastIdentityPositions.TryGetValue(identity, out (Cell2D cell, Vector2 worldPos) identityPos) || + !lastConnectionPositions.TryGetValue(newObserver, out (Cell2D cell, Vector2 worldPos) observerPos)) + return false; // If not, assume no visibility + + // Populate the pre-allocated array with visible cells from the observer's position + grid.GetNeighborCells(observerPos.cell, neighborCells); + + // Check if the object's cell is among the visible ones + for (int i = 0; i < neighborCells.Length; i++) + if (neighborCells[i].Equals(identityPos.cell)) + return true; + + return false; + } + + // Rebuilds the set of observers for a specific NetworkIdentity + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // If the object's position isn't tracked, skip rebuilding + if (!lastIdentityPositions.TryGetValue(identity, out (Cell2D cell, Vector2 worldPos) identityPos)) + return; + + // Use the precomputed observer sets to determine visibility + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + // Skip if the connection or its identity is null + if (conn?.identity == null) + continue; + + // Check if this connection can observe the identity + if (connectionObservers.TryGetValue(conn, out HashSet observers) && observers.Contains(identity)) + newObservers.Add(conn); + } + } + + public override void ResetState() + { + lastRebuildTime = 0; + // Clear and return all cell sets to the pool + for (int i = 0; i < cells.Count; i++) + { + if (cells[i] != null) + { + cells[i].Clear(); + cellPool.Push(cells[i]); + cells[i] = null; + } + } + lastIdentityPositions.Clear(); + lastConnectionPositions.Clear(); + connectionObservers.Clear(); + identityKeys.Clear(); + staticObjects.Clear(); + rebuildCounter = 0; + } + + public override void OnDestroyed(NetworkIdentity identity) + { + // If the object was tracked, remove it from its cell and position records + if (lastIdentityPositions.TryGetValue(identity, out (Cell2D cell, Vector2 worldPos) pos)) + { + int index = GetCellIndex(pos.cell); + if (index >= 0 && index < cells.Count && cells[index] != null) + { + cells[index].Remove(identity); // Remove from the cell's set + // If the cell's set is now empty, return it to the pool + if (cells[index].Count == 0) + { + cellPool.Push(cells[index]); + cells[index] = null; + } + } + lastIdentityPositions.Remove(identity); // Remove from position tracking + staticObjects.Remove(identity); // Ensure it's removed from static set if present + } + } + + // Computes a unique index for a cell in the sparse array, supporting ±9 km bounds + int GetCellIndex(Cell2D cell) + { + int qOffset = cell.q + MAX_Q / 2; // Shift -9 to 9 -> 0 to 18 + int rOffset = cell.r + MAX_R / 2; // Shift -11 to 11 -> 0 to 22 + return qOffset + rOffset * MAX_Q; + } + +#if UNITY_EDITOR + // Draws debug gizmos in the Unity Editor to visualize the 2D grid + void OnDrawGizmos() + { + // Initialize the grid if it hasn’t been created yet (e.g., before Awake) + if (grid == null) + grid = new HexGrid2D(visRange); + + // Only draw if there’s a local player to base the visualization on + if (NetworkClient.localPlayer != null) + { + Vector3 playerPosition = NetworkClient.localPlayer.transform.position; + + // Convert to grid cell using the full Vector3 for proper plane projection + Vector2 projectedPos = ProjectToGrid(playerPosition); + Cell2D playerCell = grid.WorldToCell(projectedPos); + + // Get all visible cells around the player into the pre-allocated array + grid.GetNeighborCells(playerCell, neighborCells); + + // Set gizmo color for visibility + Gizmos.color = Color.cyan; + + // Draw each visible cell as a 2D hexagon, oriented based on checkMethod + for (int i = 0; i < neighborCells.Length; i++) + { + // Convert cell to world coordinates (2D) + Vector2 worldPos2D = grid.CellToWorld(neighborCells[i]); + + // Convert to 3D position based on checkMethod + Vector3 worldPos = checkMethod == CheckMethod.XZ_FOR_3D + ? new Vector3(worldPos2D.x, 0, worldPos2D.y) // XZ plane, flat + : new Vector3(worldPos2D.x, worldPos2D.y, 0); // XY plane, vertical + + grid.DrawHexGizmo(worldPos, grid.cellRadius, checkMethod); + } + } + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs.meta new file mode 100644 index 0000000..3bcfc72 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9b8b055f11f85ff428da471a0e625dd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash2DInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs new file mode 100644 index 0000000..64415da --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs @@ -0,0 +1,336 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Spatial Hash/Hex Spatial Hash (3D)")] + public class HexSpatialHash3DInterestManagement : InterestManagement + { + [Range(1, 60), Tooltip("Time interval in seconds between observer rebuilds")] + public byte rebuildInterval = 1; + + [Range(1, 60), Tooltip("Time interval in seconds between static object rebuilds")] + public byte staticRebuildInterval = 10; + + [Range(10, 5000), Tooltip("Radius of super hex.\nSet to 10% larger than camera far clip plane.")] + public ushort visRange = 1100; + + [Range(10, 5000), Tooltip("Cell3D height effects all 3 layers")] + public ushort cellHeight = 500; + + [Range(1, 100), Tooltip("Distance an object must move for updating cell positions")] + public ushort minMoveDistance = 1; + + double lastRebuildTime; + + // Counter for batching static object updates + byte rebuildCounter = 0; + + HexGrid3D grid; + + // Sparse array mapping cell indices to sets of NetworkIdentities + readonly List> cells = new List>(); + + // Tracks the last known cell position and world position of each NetworkIdentity for efficient updates + readonly Dictionary lastIdentityPositions = new Dictionary(); + + // Tracks the last known cell position and world position of each player's connection (observer) + readonly Dictionary lastConnectionPositions = new Dictionary(); + + // Pre-allocated array for storing neighbor cells (center + 6 neighbors per layer x 3 layers) + readonly Cell3D[] neighborCells = new Cell3D[21]; + + // Maps each connection to the set of NetworkIdentities it can observe, precomputed for rebuilds + readonly Dictionary> connectionObservers = new Dictionary>(); + + // Reusable list for safe iteration over NetworkIdentities, avoiding ToList() allocations + readonly List identityKeys = new List(); + + // Pool of reusable HashSet instances to reduce allocations + readonly Stack> cellPool = new Stack>(); + + // Set of static NetworkIdentities that don't move, updated less frequently + readonly HashSet staticObjects = new HashSet(); + + // Scene bounds: ±9 km (18 km total) in each dimension + const int MAX_Q = 19; // Covers -9 to 9 (~18 km) + const int MAX_R = 23; // Covers -11 to 11 (~18 km) + const int LAYER_OFFSET = 18; // Offset for -18 to 17 layers + const int MAX_LAYERS = 36; // Total layers for ±9 km (18 km) + const ushort MAX_AREA = 9000; // Maximum area in meters + + void Awake() + { + grid = new HexGrid3D(visRange, cellHeight); + // Initialize cells list with null entries up to max size (±9 km bounds) + int maxSize = MAX_Q * MAX_R * MAX_LAYERS; + for (int i = 0; i < maxSize; i++) + cells.Add(null); + } + + void LateUpdate() + { + if (NetworkTime.time - lastRebuildTime >= rebuildInterval) + { + // Update positions of all active connections (players) in the network + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + if (conn?.identity != null) // Ensure connection and its identity exist + { + Vector3 position = conn.identity.transform.position; + // Only update if the position has changed significantly + if (!lastConnectionPositions.TryGetValue(conn, out (Cell3D cell, Vector3 worldPos) last) || + Vector3.Distance(position, last.worldPos) >= minMoveDistance) + { + Cell3D cell = grid.WorldToCell(position); // Convert world position to grid cell + lastConnectionPositions[conn] = (cell, position); // Store the player's cell and position + } + } + + // Populate the reusable list with current keys for safe iteration + identityKeys.Clear(); + identityKeys.AddRange(lastIdentityPositions.Keys); + + // Update dynamic objects every rebuild, static objects every staticRebuildInterval + bool updateStatic = rebuildCounter >= staticRebuildInterval; + foreach (NetworkIdentity identity in identityKeys) + if (updateStatic || !staticObjects.Contains(identity)) + UpdateIdentityPosition(identity); // Refresh cell position for dynamic or scheduled static objects + + if (updateStatic) + rebuildCounter = 0; // Reset the counter after updating static objects + else + rebuildCounter++; + + // Precompute observer sets for each connection before rebuilding + connectionObservers.Clear(); + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + if (conn?.identity == null || !lastConnectionPositions.TryGetValue(conn, out (Cell3D cell, Vector3 worldPos) connPos)) + continue; + + // Get cells visible from the player's position + grid.GetNeighborCells(connPos.cell, neighborCells); + + // Initialize the observer set for this connection + HashSet observers = new HashSet(); + connectionObservers[conn] = observers; + + // Add all identities in visible cells to the observer set + for (int i = 0; i < neighborCells.Length; i++) + { + int index = GetCellIndex(neighborCells[i]); + if (index >= 0 && index < cells.Count && cells[index] != null) + { + foreach (NetworkIdentity identity in cells[index]) + observers.Add(identity); + } + } + } + + // RebuildAll invokes NetworkServer.RebuildObservers on all spawned objects + base.RebuildAll(); + + // Update the last rebuild time + lastRebuildTime = NetworkTime.time; + } + } + + // Called when a new networked object is spawned on the server + public override void OnSpawned(NetworkIdentity identity) + { + // Register the new object's position in the grid system + UpdateIdentityPosition(identity); + + // Check if the object is statically batched (indicating it won't move) + Renderer[] renderers = identity.gameObject.GetComponentsInChildren(); + if (renderers.Any(r => r.isPartOfStaticBatch)) + staticObjects.Add(identity); + } + + // Updates the grid cell position of a NetworkIdentity when it moves or spawns + void UpdateIdentityPosition(NetworkIdentity identity) + { + // Get the current world position of the object + Vector3 position = identity.transform.position; + + // Convert player position to grid cell coordinates + Cell3D newCell = grid.WorldToCell(position); + + // Check if the object is within ±9 km bounds + if (Mathf.Abs(position.x) > MAX_AREA || Mathf.Abs(position.y) > MAX_AREA || Mathf.Abs(position.z) > MAX_AREA) + return; // Ignore objects outside bounds + + // Check if the object was previously tracked + if (lastIdentityPositions.TryGetValue(identity, out (Cell3D cell, Vector3 worldPos) previous)) + { + // Only update if the position has changed significantly or the cell has changed + if (Vector3.Distance(position, previous.worldPos) >= minMoveDistance || !newCell.Equals(previous.cell)) + { + if (!newCell.Equals(previous.cell)) + { + // Object moved to a new cell + // Remove it from the old cell's set and add it to the new cell's set + int oldIndex = GetCellIndex(previous.cell); + if (oldIndex >= 0 && oldIndex < cells.Count && cells[oldIndex] != null) + cells[oldIndex].Remove(identity); + AddToCell(newCell, identity); + } + // Update the stored position and cell + lastIdentityPositions[identity] = (newCell, position); + } + } + else + { + // New object - add it to the grid and track its position + AddToCell(newCell, identity); + lastIdentityPositions[identity] = (newCell, position); + } + } + + // Adds a NetworkIdentity to a specific cell's set of objects + void AddToCell(Cell3D cell, NetworkIdentity identity) + { + int index = GetCellIndex(cell); + if (index < 0 || index >= cells.Count) + return; // Out of bounds, ignore + + // If the cell doesn't exist in the array yet, fetch or create a new set from the pool + if (cells[index] == null) + { + cells[index] = cellPool.Count > 0 ? cellPool.Pop() : new HashSet(); + } + cells[index].Add(identity); + } + + // Determines if a new observer can see a given NetworkIdentity + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // Check if we have position data for both the object and the observer + if (!lastIdentityPositions.TryGetValue(identity, out (Cell3D cell, Vector3 worldPos) identityPos) || + !lastConnectionPositions.TryGetValue(newObserver, out (Cell3D cell, Vector3 worldPos) observerPos)) + return false; // If not, assume no visibility + + // Populate the pre-allocated array with visible cells from the observer's position + grid.GetNeighborCells(observerPos.cell, neighborCells); + + // Check if the object's cell is among the visible ones + for (int i = 0; i < neighborCells.Length; i++) + if (neighborCells[i].Equals(identityPos.cell)) + return true; + + return false; + } + + // Rebuilds the set of observers for a specific NetworkIdentity + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // If the object's position isn't tracked, skip rebuilding + if (!lastIdentityPositions.TryGetValue(identity, out (Cell3D cell, Vector3 worldPos) identityPos)) + return; + + // Use the precomputed observer sets to determine visibility + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + // Skip if the connection or its identity is null + if (conn?.identity == null) + continue; + + // Check if this connection can observe the identity + if (connectionObservers.TryGetValue(conn, out HashSet observers) && observers.Contains(identity)) + newObservers.Add(conn); + } + } + + public override void ResetState() + { + lastRebuildTime = 0; + // Clear and return all cell sets to the pool + for (int i = 0; i < cells.Count; i++) + { + if (cells[i] != null) + { + cells[i].Clear(); + cellPool.Push(cells[i]); + cells[i] = null; + } + } + lastIdentityPositions.Clear(); + lastConnectionPositions.Clear(); + connectionObservers.Clear(); + identityKeys.Clear(); + staticObjects.Clear(); + rebuildCounter = 0; + } + + public override void OnDestroyed(NetworkIdentity identity) + { + // If the object was tracked, remove it from its cell and position records + if (lastIdentityPositions.TryGetValue(identity, out (Cell3D cell, Vector3 worldPos) pos)) + { + int index = GetCellIndex(pos.cell); + if (index >= 0 && index < cells.Count && cells[index] != null) + { + cells[index].Remove(identity); // Remove from the cell's set + // If the cell's set is now empty, return it to the pool + if (cells[index].Count == 0) + { + cellPool.Push(cells[index]); + cells[index] = null; + } + } + lastIdentityPositions.Remove(identity); // Remove from position tracking + staticObjects.Remove(identity); // Ensure it's removed from static set if present + } + } + + // Computes a unique index for a cell in the sparse array, supporting ±9 km bounds + int GetCellIndex(Cell3D cell) + { + int qOffset = cell.q + MAX_Q / 2; // Shift -9 to 9 -> 0 to 18 + int rOffset = cell.r + MAX_R / 2; // Shift -11 to 11 -> 0 to 22 + int layerOffset = cell.layer + LAYER_OFFSET; // Shift -18 to 17 -> 0 to 35 + return qOffset + rOffset * MAX_Q + layerOffset * MAX_Q * MAX_R; + } + +#if UNITY_EDITOR + + // Draws debug gizmos in the Unity Editor to visualize the grid + void OnDrawGizmos() + { + // Initialize the grid if it hasn't been created yet (e.g., before Awake) + if (grid == null) + grid = new HexGrid3D(visRange, cellHeight); + + // Only draw if there's a local player to base the visualization on + if (NetworkClient.localPlayer != null) + { + Vector3 playerPosition = NetworkClient.localPlayer.transform.position; + + // Convert to grid cell + Cell3D playerCell = grid.WorldToCell(playerPosition); + + // Get all visible cells around the player into the pre-allocated array + grid.GetNeighborCells(playerCell, neighborCells); + + // Set default gizmo color (though overridden per cell) + Gizmos.color = Color.cyan; + + // Draw each visible cell as a hexagonal prism + for (int i = 0; i < neighborCells.Length; i++) + { + // Convert cell to world coordinates + Vector3 worldPos = grid.CellToWorld(neighborCells[i]); + + // Determine the layer relative to the player's cell for color coding + int relativeLayer = neighborCells[i].layer - playerCell.layer; + + // Draw the hexagonal cell with appropriate color based on layer + grid.DrawHexGizmo(worldPos, grid.cellRadius, grid.cellHeight, relativeLayer); + } + } + } + +#endif + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs.meta new file mode 100644 index 0000000..9931906 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 58e492e77a2a1a3488412ceed5c2aa2d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/HexSpatialHash3DInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs new file mode 100644 index 0000000..1953de7 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs @@ -0,0 +1,146 @@ +// extremely fast spatial hashing interest management based on uMMORPG GridChecker. +// => 30x faster in initial tests +// => scales way higher +// checks on three dimensions (XYZ) which includes the vertical axes. +// this is slower than XY checking for regular spatial hashing. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Spatial Hash/Spatial Hashing Interest Management")] + public class SpatialHashing3DInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 30; + + // we use a 9 neighbour grid. + // so we always see in a distance of 2 grids. + // for example, our own grid and then one on top / below / left / right. + // + // this means that grid resolution needs to be distance / 2. + // so for example, for distance = 30 we see 2 cells = 15 * 2 distance. + // + // on first sight, it seems we need distance / 3 (we see left/us/right). + // but that's not the case. + // resolution would be 10, and we only see 1 cell far, so 10+10=20. + public int resolution => visRange / 2; // same as XY because if XY is rotated 90 degree for 3D, it's still the same distance + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + [Header("Debug Settings")] + public bool showSlider; + + // the grid + // begin with a large capacity to avoid resizing & allocations. + Grid3D grid = new Grid3D(1024); + + // project 3d world position to grid position + Vector3Int ProjectToGrid(Vector3 position) => + Vector3Int.RoundToInt(position / resolution); + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // calculate projected positions + Vector3Int projected = ProjectToGrid(identity.transform.position); + Vector3Int observerProjected = ProjectToGrid(newObserver.identity.transform.position); + + // distance needs to be at max one of the 8 neighbors, which is + // 1 for the direct neighbors + // 1.41 for the diagonal neighbors (= sqrt(2)) + // => use sqrMagnitude and '2' to avoid computations. same result. + return (projected - observerProjected).sqrMagnitude <= 2; // same as XY because if XY is rotated 90 degree for 3D, it's still the same distance + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // add everyone in 9 neighbour grid + // -> pass observers to GetWithNeighbours directly to avoid allocations + // and expensive .UnionWith computations. + Vector3Int current = ProjectToGrid(identity.transform.position); + grid.GetWithNeighbours(current, newObservers); + } + + [ServerCallback] + public override void ResetState() + { + lastRebuildTime = 0D; + } + + // update everyone's position in the grid + // (internal so we can update from tests) + [ServerCallback] + internal void Update() + { + // NOTE: unlike Scene/MatchInterestManagement, this rebuilds ALL + // entities every INTERVAL. consider the other approach later. + + // IMPORTANT: refresh grid every update! + // => newly spawned entities get observers assigned via + // OnCheckObservers. this can happen any time and we don't want + // them broadcast to old (moved or destroyed) connections. + // => players do move all the time. we want them to always be in the + // correct grid position. + // => note that the actual 'rebuildall' doesn't need to happen all + // the time. + // NOTE: consider refreshing grid only every 'interval' too. but not + // for now. stability & correctness matter. + + // clear old grid results before we update everyone's position. + // (this way we get rid of destroyed connections automatically) + // + // NOTE: keeps allocated HashSets internally. + // clearing & populating every frame works without allocations + grid.ClearNonAlloc(); + + // put every connection into the grid at it's main player's position + // NOTE: player sees in a radius around him. NOT around his pet too. + foreach (NetworkConnectionToClient connection in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (connection.isAuthenticated && connection.identity != null) + { + // calculate current grid position + Vector3Int position = ProjectToGrid(connection.identity.transform.position); + + // put into grid + grid.Add(position, connection); + } + } + + // rebuild all spawned entities' observers every 'interval' + // this will call OnRebuildObservers which then returns the + // observers at grid[position] for each entity. + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + } + +// OnGUI allocates even if it does nothing. avoid in release. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // slider from dotsnet. it's nice to play around with in the benchmark + // demo. + void OnGUI() + { + if (!showSlider) return; + + // only show while server is running. not on client, etc. + if (!NetworkServer.active) return; + + int height = 30; + int width = 250; + GUILayout.BeginArea(new Rect(Screen.width / 2 - width / 2, Screen.height - height, width, height)); + GUILayout.BeginHorizontal("Box"); + GUILayout.Label("Radius:"); + visRange = Mathf.RoundToInt(GUILayout.HorizontalSlider(visRange, 0, 200, GUILayout.Width(150))); + GUILayout.Label(visRange.ToString()); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } +#endif + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta new file mode 100644 index 0000000..dfd947a --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 120b4d6121d94e0280cd2ec536b0ea8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashing3DInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs new file mode 100644 index 0000000..0cb5e23 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs @@ -0,0 +1,156 @@ +// extremely fast spatial hashing interest management based on uMMORPG GridChecker. +// => 30x faster in initial tests +// => scales way higher +// checks on two dimensions only(!), for example: XZ for 3D games or XY for 2D games. +// this is faster than XYZ checking but doesn't check vertical distance. +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Spatial Hash/Spatial Hashing Interest Management")] + public class SpatialHashingInterestManagement : InterestManagement + { + [Tooltip("The maximum range that objects will be visible at.")] + public int visRange = 30; + + // we use a 9 neighbour grid. + // so we always see in a distance of 2 grids. + // for example, our own grid and then one on top / below / left / right. + // + // this means that grid resolution needs to be distance / 2. + // so for example, for distance = 30 we see 2 cells = 15 * 2 distance. + // + // on first sight, it seems we need distance / 3 (we see left/us/right). + // but that's not the case. + // resolution would be 10, and we only see 1 cell far, so 10+10=20. + public int resolution => visRange / 2; + + [Tooltip("Rebuild all every 'rebuildInterval' seconds.")] + public float rebuildInterval = 1; + double lastRebuildTime; + + public enum CheckMethod + { + XZ_FOR_3D, + XY_FOR_2D + } + [Tooltip("Spatial Hashing supports 3D (XZ) and 2D (XY) games.")] + public CheckMethod checkMethod = CheckMethod.XZ_FOR_3D; + + [Header("Debug Settings")] + public bool showSlider; + + // the grid + // begin with a large capacity to avoid resizing & allocations. + Grid2D grid = new Grid2D(1024); + + // project 3d world position to grid position + Vector2Int ProjectToGrid(Vector3 position) => + checkMethod == CheckMethod.XZ_FOR_3D + ? Vector2Int.RoundToInt(new Vector2(position.x, position.z) / resolution) + : Vector2Int.RoundToInt(new Vector2(position.x, position.y) / resolution); + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // calculate projected positions + Vector2Int projected = ProjectToGrid(identity.transform.position); + Vector2Int observerProjected = ProjectToGrid(newObserver.identity.transform.position); + + // distance needs to be at max one of the 8 neighbors, which is + // 1 for the direct neighbors + // 1.41 for the diagonal neighbors (= sqrt(2)) + // => use sqrMagnitude and '2' to avoid computations. same result. + return (projected - observerProjected).sqrMagnitude <= 2; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // add everyone in 9 neighbour grid + // -> pass observers to GetWithNeighbours directly to avoid allocations + // and expensive .UnionWith computations. + Vector2Int current = ProjectToGrid(identity.transform.position); + grid.GetWithNeighbours(current, newObservers); + } + + [ServerCallback] + public override void ResetState() + { + lastRebuildTime = 0D; + } + + // update everyone's position in the grid + // (internal so we can update from tests) + [ServerCallback] + internal void Update() + { + // NOTE: unlike Scene/MatchInterestManagement, this rebuilds ALL + // entities every INTERVAL. consider the other approach later. + + // IMPORTANT: refresh grid every update! + // => newly spawned entities get observers assigned via + // OnCheckObservers. this can happen any time and we don't want + // them broadcast to old (moved or destroyed) connections. + // => players do move all the time. we want them to always be in the + // correct grid position. + // => note that the actual 'rebuildall' doesn't need to happen all + // the time. + // NOTE: consider refreshing grid only every 'interval' too. but not + // for now. stability & correctness matter. + + // clear old grid results before we update everyone's position. + // (this way we get rid of destroyed connections automatically) + // + // NOTE: keeps allocated HashSets internally. + // clearing & populating every frame works without allocations + grid.ClearNonAlloc(); + + // put every connection into the grid at it's main player's position + // NOTE: player sees in a radius around him. NOT around his pet too. + foreach (NetworkConnectionToClient connection in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (connection.isAuthenticated && connection.identity != null) + { + // calculate current grid position + Vector2Int position = ProjectToGrid(connection.identity.transform.position); + + // put into grid + grid.Add(position, connection); + } + } + + // rebuild all spawned entities' observers every 'interval' + // this will call OnRebuildObservers which then returns the + // observers at grid[position] for each entity. + if (NetworkTime.localTime >= lastRebuildTime + rebuildInterval) + { + RebuildAll(); + lastRebuildTime = NetworkTime.localTime; + } + } + +// OnGUI allocates even if it does nothing. avoid in release. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // slider from dotsnet. it's nice to play around with in the benchmark + // demo. + void OnGUI() + { + if (!showSlider) return; + + // only show while server is running. not on client, etc. + if (!NetworkServer.active) return; + + int height = 30; + int width = 250; + GUILayout.BeginArea(new Rect(Screen.width / 2 - width / 2, Screen.height - height, width, height)); + GUILayout.BeginHorizontal("Box"); + GUILayout.Label("Radius:"); + visRange = Mathf.RoundToInt(GUILayout.HorizontalSlider(visRange, 0, 200, GUILayout.Width(150))); + GUILayout.Label(visRange.ToString()); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } +#endif + } +} diff --git a/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta new file mode 100644 index 0000000..eb61d5e --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 39adc6e09d5544ed955a50ce8600355a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/SpatialHashing/SpatialHashingInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Team.meta b/Assets/Mirror/Components/InterestManagement/Team.meta new file mode 100644 index 0000000..fe40aa4 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Team.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d418e60072433b4bbebbf5f3a7de1bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs b/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs new file mode 100644 index 0000000..290eb06 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs @@ -0,0 +1,39 @@ +// simple component that holds team information +using System; +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Interest Management/ Team/Network Team")] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public class NetworkTeam : NetworkBehaviour + { + [SerializeField] + [Tooltip("Set teamId on Server at runtime to the same value on all networked objects that belong to a given team")] + string _teamId; + + public string teamId + { + get => _teamId; + set + { + if (Application.IsPlaying(gameObject) && !NetworkServer.active) + throw new InvalidOperationException("teamId can only be set at runtime on active server"); + + if (_teamId == value) + return; + + string oldTeam = _teamId; + _teamId = value; + + //Only inform the AOI if this netIdentity has been spawned(isServer) and only if using a TeamInterestManagement + if (isServer && NetworkServer.aoi is TeamInterestManagement teamInterestManagement) + teamInterestManagement.OnTeamChanged(this, oldTeam); + } + } + + [Tooltip("When enabled this object is visible to all clients. Typically this would be true for player objects")] + public bool forceShown; + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs.meta b/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs.meta new file mode 100644 index 0000000..71ad16a --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2576730625b1632468cbcbfe5e721f88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Team/NetworkTeam.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs new file mode 100644 index 0000000..cb5bdb7 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs @@ -0,0 +1,182 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/ Interest Management/ Team/Team Interest Management")] + public class TeamInterestManagement : InterestManagement + { + readonly Dictionary> teamObjects = + new Dictionary>(); + + readonly HashSet dirtyTeams = new HashSet(); + + // LateUpdate so that all spawns/despawns/changes are done + [ServerCallback] + void LateUpdate() + { + // Rebuild all dirty teams + // dirtyTeams will be empty if no teams changed members + // by spawning or destroying or changing teamId in this frame. + foreach (string dirtyTeam in dirtyTeams) + { + // rebuild always, even if teamObjects[dirtyTeam] is empty. + // Players might have left the team, but they may still be spawned. + RebuildTeamObservers(dirtyTeam); + + // clean up empty entries in the dict + if (teamObjects[dirtyTeam].Count == 0) + teamObjects.Remove(dirtyTeam); + } + + dirtyTeams.Clear(); + } + + [ServerCallback] + void RebuildTeamObservers(string teamId) + { + foreach (NetworkTeam networkTeam in teamObjects[teamId]) + if (networkTeam.netIdentity != null) + NetworkServer.RebuildObservers(networkTeam.netIdentity, false); + } + + // called by NetworkTeam.teamId setter + [ServerCallback] + internal void OnTeamChanged(NetworkTeam networkTeam, string oldTeam) + { + // This object is in a new team so observers in the prior team + // and the new team need to rebuild their respective observers lists. + + // Remove this object from the hashset of the team it just left + // Null / Empty string is never a valid teamId + if (!string.IsNullOrWhiteSpace(oldTeam)) + { + dirtyTeams.Add(oldTeam); + teamObjects[oldTeam].Remove(networkTeam); + } + + // Null / Empty string is never a valid teamId + if (string.IsNullOrWhiteSpace(networkTeam.teamId)) + return; + + dirtyTeams.Add(networkTeam.teamId); + + // Make sure this new team is in the dictionary + if (!teamObjects.ContainsKey(networkTeam.teamId)) + teamObjects[networkTeam.teamId] = new HashSet(); + + // Add this object to the hashset of the new team + teamObjects[networkTeam.teamId].Add(networkTeam); + } + + [ServerCallback] + public override void OnSpawned(NetworkIdentity identity) + { + if (!identity.TryGetComponent(out NetworkTeam networkTeam)) + return; + + string networkTeamId = networkTeam.teamId; + + // Null / Empty string is never a valid teamId...do not add to teamObjects collection + if (string.IsNullOrWhiteSpace(networkTeamId)) + return; + + // Debug.Log($"TeamInterestManagement.OnSpawned({identity.name}) currentTeam: {currentTeam}"); + if (!teamObjects.TryGetValue(networkTeamId, out HashSet objects)) + { + objects = new HashSet(); + teamObjects.Add(networkTeamId, objects); + } + + objects.Add(networkTeam); + + // Team ID could have been set in NetworkBehaviour::OnStartServer on this object. + // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here. + // Add the current team to dirtyTeames for LateUpdate to rebuild it. + dirtyTeams.Add(networkTeamId); + } + + [ServerCallback] + public override void OnDestroyed(NetworkIdentity identity) + { + // Don't RebuildSceneObservers here - that will happen in LateUpdate. + // Multiple objects could be destroyed in same frame and we don't + // want to rebuild for each one...let LateUpdate do it once. + // We must add the current team to dirtyTeames for LateUpdate to rebuild it. + if (identity.TryGetComponent(out NetworkTeam currentTeam)) + { + if (!string.IsNullOrWhiteSpace(currentTeam.teamId) && + teamObjects.TryGetValue(currentTeam.teamId, out HashSet objects) && + objects.Remove(currentTeam)) + dirtyTeams.Add(currentTeam.teamId); + } + } + + public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver) + { + // Always observed if no NetworkTeam component + if (!identity.TryGetComponent(out NetworkTeam identityNetworkTeam)) + return true; + + if (identityNetworkTeam.forceShown) + return true; + + // Null / Empty string is never a valid teamId + if (string.IsNullOrWhiteSpace(identityNetworkTeam.teamId)) + return false; + + // Always observed if no NetworkTeam component + if (!newObserver.identity.TryGetComponent(out NetworkTeam newObserverNetworkTeam)) + return true; + + // Null / Empty string is never a valid teamId + if (string.IsNullOrWhiteSpace(newObserverNetworkTeam.teamId)) + return false; + + //Debug.Log($"TeamInterestManagement.OnCheckObserver {identity.name} {identityNetworkTeam.teamId} | {newObserver.identity.name} {newObserverNetworkTeam.teamId}"); + + // Observed only if teamId's team + return identityNetworkTeam.teamId == newObserverNetworkTeam.teamId; + } + + public override void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers) + { + // If this object doesn't have a NetworkTeam then it's visible to all clients + if (!identity.TryGetComponent(out NetworkTeam networkTeam)) + { + AddAllConnections(newObservers); + return; + } + + // If this object has NetworkTeam and forceShown == true then it's visible to all clients + if (networkTeam.forceShown) + { + AddAllConnections(newObservers); + return; + } + + // Null / Empty string is never a valid teamId + if (string.IsNullOrWhiteSpace(networkTeam.teamId)) + return; + + // Abort if this team hasn't been created yet by OnSpawned or OnTeamChanged + if (!teamObjects.TryGetValue(networkTeam.teamId, out HashSet objects)) + return; + + // Add everything in the hashset for this object's current team + foreach (NetworkTeam netTeam in objects) + if (netTeam.netIdentity != null && netTeam.netIdentity.connectionToClient != null) + newObservers.Add(netTeam.netIdentity.connectionToClient); + } + + void AddAllConnections(HashSet newObservers) + { + foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values) + { + // authenticated and joined world with a player? + if (conn != null && conn.isAuthenticated && conn.identity != null) + newObservers.Add(conn); + } + } + } +} diff --git a/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs.meta b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs.meta new file mode 100644 index 0000000..2bf3f09 --- /dev/null +++ b/Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: dceb9a7085758fd4590419ff5b14b636 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/InterestManagement/Team/TeamInterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/LagCompensation.meta b/Assets/Mirror/Components/LagCompensation.meta new file mode 100644 index 0000000..669a5b8 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 00ac1d0527f234939aba22b4d7cbf280 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs new file mode 100644 index 0000000..876eb18 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs @@ -0,0 +1,109 @@ +// Applies HistoryBounds to the physics world by projecting to a trigger Collider. +// This way we can use Physics.Raycast on it. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Lag Compensation/ History Collider")] + public class HistoryCollider : MonoBehaviour + { + [Header("Components")] + [Tooltip("The object's actual collider. We need to know where it is, and how large it is.")] + public Collider actualCollider; + + [Tooltip("The helper collider that the history bounds are projected onto.\nNeeds to be added to a child GameObject to counter-rotate an axis aligned Bounding Box onto it.\nThis is only used by this component.")] + public BoxCollider boundsCollider; + + [Header("History")] + [Tooltip("Keep this many past bounds in the buffer. The larger this is, the further we can raycast into the past.\nMaximum time := historyAmount * captureInterval")] + public int boundsLimit = 8; + + [Tooltip("Gather N bounds at a time into a bucket for faster encapsulation. A factor of 2 will be twice as fast, etc.")] + public int boundsPerBucket = 2; + + [Tooltip("Capture bounds every 'captureInterval' seconds. Larger values will require fewer computations, but may not capture every small move.")] + public float captureInterval = 0.100f; // 100 ms + double lastCaptureTime = 0; + + [Header("Debug")] + public Color historyColor = new Color(1.0f, 0.5f, 0.0f, 1.0f); + public Color currentColor = Color.red; + + protected HistoryBounds history = null; + + protected virtual void Awake() + { + history = new HistoryBounds(boundsLimit, boundsPerBucket); + + // ensure colliders were set. + // bounds collider should always be a trigger. + if (actualCollider == null) Debug.LogError("HistoryCollider: actualCollider was not set."); + if (boundsCollider == null) Debug.LogError("HistoryCollider: boundsCollider was not set."); + if (boundsCollider.transform.parent != transform) Debug.LogError("HistoryCollider: boundsCollider must be a child of this GameObject."); + if (!boundsCollider.isTrigger) Debug.LogError("HistoryCollider: boundsCollider must be a trigger."); + } + + // capturing and projecting onto colliders should use physics update + protected virtual void FixedUpdate() + { + // capture current bounds every interval + if (NetworkTime.localTime >= lastCaptureTime + captureInterval) + { + lastCaptureTime = NetworkTime.localTime; + CaptureBounds(); + } + + // project bounds onto helper collider + ProjectBounds(); + } + + protected virtual void CaptureBounds() + { + // grab current collider bounds + // this is in world space coordinates, and axis aligned + // TODO double check + Bounds bounds = actualCollider.bounds; + + // insert into history + history.Insert(bounds); + } + + protected virtual void ProjectBounds() + { + // grab total collider encapsulating all of history + Bounds total = history.total; + + // don't assign empty bounds, this will throw a Unity warning + if (history.boundsCount == 0) return; + + // scale projection doesn't work yet. + // for now, don't allow scale changes. + if (transform.lossyScale != Vector3.one) + { + Debug.LogWarning($"HistoryCollider: {name}'s transform global scale must be (1,1,1)."); + return; + } + + // counter rotate the child collider against the gameobject's rotation. + // we need this to always be axis aligned. + boundsCollider.transform.localRotation = Quaternion.Inverse(transform.rotation); + + // project world space bounds to collider's local space + boundsCollider.center = boundsCollider.transform.InverseTransformPoint(total.center); + boundsCollider.size = total.size; // TODO projection? + } + + // TODO runtime drawing for debugging? + protected virtual void OnDrawGizmos() + { + // draw total bounds + Gizmos.color = historyColor; + Gizmos.DrawWireCube(history.total.center, history.total.size); + + // draw current bounds + Gizmos.color = currentColor; + Gizmos.DrawWireCube(actualCollider.bounds.center, actualCollider.bounds.size); + } + } +} diff --git a/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta new file mode 100644 index 0000000..e267f0a --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/HistoryCollider.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f5f2158d9776d4b569858f793be4da60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/LagCompensation/HistoryCollider.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs new file mode 100644 index 0000000..63669c0 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs @@ -0,0 +1,197 @@ +// Add this component to a Player object with collider. +// Automatically keeps a history for lag compensation. +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public struct Capture3D : Capture + { + public double timestamp { get; set; } + public Vector3 position; + public Vector3 size; + + public Capture3D(double timestamp, Vector3 position, Vector3 size) + { + this.timestamp = timestamp; + this.position = position; + this.size = size; + } + + public void DrawGizmo() + { + Gizmos.DrawWireCube(position, size); + } + + public static Capture3D Interpolate(Capture3D from, Capture3D to, double t) => + new Capture3D( + 0, // interpolated snapshot is applied directly. don't need timestamps. + Vector3.LerpUnclamped(from.position, to.position, (float)t), + Vector3.LerpUnclamped(from.size, to.size, (float)t) + ); + + public override string ToString() => $"(time={timestamp} pos={position} size={size})"; + } + + [DisallowMultipleComponent] + [AddComponentMenu("Network/ Lag Compensation/ Lag Compensator")] + [HelpURL("https://mirror-networking.gitbook.io/docs/manual/general/lag-compensation")] + public class LagCompensator : NetworkBehaviour + { + [Header("Components")] + [Tooltip("The collider to keep a history of.")] + public Collider trackedCollider; // assign this in inspector + + [Header("Settings")] + public LagCompensationSettings lagCompensationSettings = new LagCompensationSettings(); + double lastCaptureTime; + + // lag compensation history of + readonly Queue> history = new Queue>(); + + [Header("Debugging")] + public Color historyColor = Color.white; + + [ServerCallback] + protected virtual void Update() + { + // capture lag compensation snapshots every interval. + // NetworkTime.localTime because Unity 2019 doesn't have 'double' time yet. + if (NetworkTime.localTime >= lastCaptureTime + lagCompensationSettings.captureInterval) + { + lastCaptureTime = NetworkTime.localTime; + Capture(); + } + } + + [ServerCallback] + protected virtual void Capture() + { + // capture current state + Capture3D capture = new Capture3D( + NetworkTime.localTime, + trackedCollider.bounds.center, + trackedCollider.bounds.size + ); + + // insert into history + LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + } + + protected virtual void OnDrawGizmos() + { + // draw history + Gizmos.color = historyColor; + LagCompensation.DrawGizmos(history); + } + + // sampling //////////////////////////////////////////////////////////// + // sample the sub-tick (=interpolated) history of this object for a hit test. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + [ServerCallback] + public virtual bool Sample(NetworkConnectionToClient viewer, out Capture3D sample) + { + // never trust the client: estimate client time instead. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // the estimation is very good. the error is as low as ~6ms for the demo. + // note that passing 'rtt' is fine: EstimateTime halves it to latency. + double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, viewer.rtt, NetworkClient.bufferTime); + + // sample the history to get the nearest snapshots around 'timestamp' + if (LagCompensation.Sample(history, estimatedTime, lagCompensationSettings.captureInterval, out Capture3D resultBefore, out Capture3D resultAfter, out double t)) + { + // interpolate to get a decent estimation at exactly 'timestamp' + sample = Capture3D.Interpolate(resultBefore, resultAfter, t); + return true; + } + else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}"); + + sample = default; + return false; + } + + // convenience tests /////////////////////////////////////////////////// + // there are multiple different ways to check a hit against the sample: + // - raycasting + // - bounds.contains + // - increasing bounds by tolerance and checking contains + // - threshold to bounds.closestpoint + // let's offer a few solutions directly and see which users prefer. + + // bounds check: checks distance to closest point on bounds in history @ -rtt. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + // this is super simple and fast, but not 100% physically accurate since we don't raycast. + [ServerCallback] + public virtual bool BoundsCheck( + NetworkConnectionToClient viewer, + Vector3 hitPoint, + float toleranceDistance, + out float distance, + out Vector3 nearest) + { + // first, sample the history at -rtt of the viewer. + if (Sample(viewer, out Capture3D capture)) + { + // now that we know where the other player was at that time, + // we can see if the hit point was within tolerance of it. + // TODO consider rotations??? + // TODO consider original collider shape?? + Bounds bounds = new Bounds(capture.position, capture.size); + nearest = bounds.ClosestPoint(hitPoint); + distance = Vector3.Distance(nearest, hitPoint); + return distance <= toleranceDistance; + } + nearest = hitPoint; + distance = 0; + return false; + } + + // raycast check: creates a collider the sampled position and raycasts to hitPoint. + // 'viewer' needs to be the player who fired! + // for example, if A fires at B, then call B.Sample(viewer, point, tolerance). + // this is physically accurate (checks against walls etc.), with the cost + // of a runtime instantiation. + // + // originPoint: where the player fired the weapon. + // hitPoint: where the player's local raycast hit. + // tolerance: scale up the sampled collider by % in order to have a bit of a tolerance. + // 0 means no extra tolerance, 0.05 means 5% extra tolerance. + // layerMask: the layer mask to use for the raycast. + [ServerCallback] + public virtual bool RaycastCheck( + NetworkConnectionToClient viewer, + Vector3 originPoint, + Vector3 hitPoint, + float tolerancePercent, + int layerMask, + out RaycastHit hit) + { + // first, sample the history at -rtt of the viewer. + if (Sample(viewer, out Capture3D capture)) + { + // instantiate a real physics collider on demand. + // TODO rotation?? + // TODO different collier types?? + GameObject temp = new GameObject("LagCompensatorTest"); + temp.transform.position = capture.position; + BoxCollider tempCollider = temp.AddComponent(); + tempCollider.size = capture.size * (1 + tolerancePercent); + + // raycast + Vector3 direction = hitPoint - originPoint; + float maxDistance = direction.magnitude * 2; + bool result = Physics.Raycast(originPoint, direction, out hit, maxDistance, layerMask); + + // cleanup + Destroy(temp); + return result; + } + + hit = default; + return false; + } + } +} diff --git a/Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta new file mode 100644 index 0000000..e13b9c0 --- /dev/null +++ b/Assets/Mirror/Components/LagCompensation/LagCompensator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a898831dd60c4cdfbfd9a6ea5702ed01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/LagCompensation/LagCompensator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef b/Assets/Mirror/Components/Mirror.Components.asmdef new file mode 100644 index 0000000..90c360e --- /dev/null +++ b/Assets/Mirror/Components/Mirror.Components.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Mirror.Components", + "rootNamespace": "", + "references": [ + "GUID:30817c1a0e6d646d99c048fc403f5979" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Mirror.Components.asmdef.meta b/Assets/Mirror/Components/Mirror.Components.asmdef.meta new file mode 100644 index 0000000..79c4587 --- /dev/null +++ b/Assets/Mirror/Components/Mirror.Components.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 72872094b21c16e48b631b2224833d49 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Mirror.Components.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkAnimator.cs b/Assets/Mirror/Components/NetworkAnimator.cs new file mode 100644 index 0000000..b573ad7 --- /dev/null +++ b/Assets/Mirror/Components/NetworkAnimator.cs @@ -0,0 +1,662 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Mirror +{ + /// + /// A component to synchronize Mecanim animation states for networked objects. + /// + /// + /// The animation of game objects can be networked by this component. There are two models of authority for networked movement: + /// If the object has authority on the client, then it should be animated locally on the owning client. The animation state information will be sent from the owning client to the server, then broadcast to all of the other clients. This is common for player objects. + /// If the object has authority on the server, then it should be animated on the server and state information will be sent to all clients. This is common for objects not related to a specific client, such as an enemy unit. + /// The NetworkAnimator synchronizes all animation parameters of the selected Animator. It does not automatically synchronize triggers. The function SetTrigger can by used by an object with authority to fire an animation trigger on other clients. + /// + // [RequireComponent(typeof(NetworkIdentity))] disabled to allow child NetworkBehaviours + [AddComponentMenu("Network/Network Animator")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-animator")] + public class NetworkAnimator : NetworkBehaviour + { + [Header("Authority")] + [Tooltip("Set to true if animations come from owner client, set to false if animations always come from server")] + public bool clientAuthority; + + /// + /// The animator component to synchronize. + /// + [FormerlySerializedAs("m_Animator")] + [Header("Animator")] + [Tooltip("Animator that will have parameters synchronized")] + public Animator animator; + + /// + /// Syncs animator.speed. + /// Default to 1 because Animator.speed defaults to 1. + /// + [SyncVar(hook = nameof(OnAnimatorSpeedChanged))] + float animatorSpeed = 1f; + float previousSpeed = 1f; + + // Note: not an object[] array because otherwise initialization is real annoying + int[] lastIntParameters; + float[] lastFloatParameters; + bool[] lastBoolParameters; + AnimatorControllerParameter[] parameters; + + // multiple layers + int[] animationHash; + int[] transitionHash; + float[] layerWeight; + double nextSendTime; + + bool SendMessagesAllowed + { + get + { + if (isServer) + { + if (!clientAuthority) + return true; + + // This is a special case where we have client authority but we have not assigned the client who has + // authority over it, no animator data will be sent over the network by the server. + // + // So we check here for a connectionToClient and if it is null we will + // let the server send animation data until we receive an owner. + if (netIdentity != null && netIdentity.connectionToClient == null) + return true; + } + + return (isOwned && clientAuthority); + } + } + + void Initialize() + { + // store the animator parameters in a variable - the "Animator.parameters" getter allocates + // a new parameter array every time it is accessed so we should avoid doing it in a loop + parameters = animator.parameters + .Where(par => !animator.IsParameterControlledByCurve(par.nameHash)) + .ToArray(); + lastIntParameters = new int[parameters.Length]; + lastFloatParameters = new float[parameters.Length]; + lastBoolParameters = new bool[parameters.Length]; + + animationHash = new int[animator.layerCount]; + transitionHash = new int[animator.layerCount]; + layerWeight = new float[animator.layerCount]; + } + + // fix https://github.com/MirrorNetworking/Mirror/issues/2810 + // both Awake and Enable need to initialize arrays. + // in case users call SetActive(false) -> SetActive(true). + void Awake() => Initialize(); + void OnEnable() => Initialize(); + + public virtual void Reset() + { + syncDirection = SyncDirection.ClientToServer; + } + + void FixedUpdate() + { + if (!SendMessagesAllowed) + return; + + if (!animator.enabled) + return; + + CheckSendRate(); + + for (int i = 0; i < animator.layerCount; i++) + { + int stateHash; + float normalizedTime; + if (!CheckAnimStateChanged(out stateHash, out normalizedTime, i)) + { + continue; + } + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + WriteParameters(writer); + SendAnimationMessage(stateHash, normalizedTime, i, layerWeight[i], writer.ToArray()); + } + } + + CheckSpeed(); + } + + void CheckSpeed() + { + float newSpeed = animator.speed; + if (Mathf.Abs(previousSpeed - newSpeed) > 0.001f) + { + previousSpeed = newSpeed; + if (isServer) + { + animatorSpeed = newSpeed; + } + else if (isClient) + { + CmdSetAnimatorSpeed(newSpeed); + } + } + } + + void OnAnimatorSpeedChanged(float _, float value) + { + // skip if host or client with authority + // they will have already set the speed so don't set again + if (isServer || (isOwned && clientAuthority)) + return; + + animator.speed = value; + } + + bool CheckAnimStateChanged(out int stateHash, out float normalizedTime, int layerId) + { + bool change = false; + stateHash = 0; + normalizedTime = 0; + + float lw = animator.GetLayerWeight(layerId); + if (Mathf.Abs(lw - layerWeight[layerId]) > 0.001f) + { + layerWeight[layerId] = lw; + change = true; + } + + if (animator.IsInTransition(layerId)) + { + AnimatorTransitionInfo tt = animator.GetAnimatorTransitionInfo(layerId); + if (tt.fullPathHash != transitionHash[layerId]) + { + // first time in this transition + transitionHash[layerId] = tt.fullPathHash; + animationHash[layerId] = 0; + return true; + } + return change; + } + + AnimatorStateInfo st = animator.GetCurrentAnimatorStateInfo(layerId); + if (st.fullPathHash != animationHash[layerId]) + { + // first time in this animation state + if (animationHash[layerId] != 0) + { + // came from another animation directly - from Play() + stateHash = st.fullPathHash; + normalizedTime = st.normalizedTime; + } + transitionHash[layerId] = 0; + animationHash[layerId] = st.fullPathHash; + return true; + } + return change; + } + + void CheckSendRate() + { + double now = NetworkTime.localTime; + if (SendMessagesAllowed && syncInterval >= 0 && now > nextSendTime) + { + nextSendTime = now + syncInterval; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + if (WriteParameters(writer)) + SendAnimationParametersMessage(writer.ToArray()); + } + } + } + + void SendAnimationMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + if (isServer) + { + RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + else if (isClient) + { + CmdOnAnimationServerMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + } + + void SendAnimationParametersMessage(byte[] parameters) + { + if (isServer) + { + RpcOnAnimationParametersClientMessage(parameters); + } + else if (isClient) + { + CmdOnAnimationParametersServerMessage(parameters); + } + } + + void HandleAnimMsg(int stateHash, float normalizedTime, int layerId, float weight, NetworkReader reader) + { + if (isOwned && clientAuthority) + return; + + // usually transitions will be triggered by parameters, if not, play anims directly. + // NOTE: this plays "animations", not transitions, so any transitions will be skipped. + // NOTE: there is no API to play a transition(?) + if (stateHash != 0 && animator.enabled) + { + animator.Play(stateHash, layerId, normalizedTime); + } + + animator.SetLayerWeight(layerId, weight); + + ReadParameters(reader); + } + + void HandleAnimParamsMsg(NetworkReader reader) + { + if (isOwned && clientAuthority) + return; + + ReadParameters(reader); + } + + void HandleAnimTriggerMsg(int hash) + { + if (animator.enabled) + animator.SetTrigger(hash); + } + + void HandleAnimResetTriggerMsg(int hash) + { + if (animator.enabled) + animator.ResetTrigger(hash); + } + + ulong NextDirtyBits() + { + ulong dirtyBits = 0; + for (int i = 0; i < parameters.Length; i++) + { + AnimatorControllerParameter par = parameters[i]; + bool changed = false; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = animator.GetInteger(par.nameHash); + changed = newIntValue != lastIntParameters[i]; + if (changed) + lastIntParameters[i] = newIntValue; + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = animator.GetFloat(par.nameHash); + changed = Mathf.Abs(newFloatValue - lastFloatParameters[i]) > 0.001f; + // only set lastValue if it was changed, otherwise value could slowly drift within the 0.001f limit each frame + if (changed) + lastFloatParameters[i] = newFloatValue; + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = animator.GetBool(par.nameHash); + changed = newBoolValue != lastBoolParameters[i]; + if (changed) + lastBoolParameters[i] = newBoolValue; + } + if (changed) + { + dirtyBits |= 1ul << i; + } + } + return dirtyBits; + } + + bool WriteParameters(NetworkWriter writer, bool forceAll = false) + { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize parameterCount to be 100% sure we deserialize correct amount of bytes. + // (255 parameters should be enough for everyone, write it as byte) + byte parameterCount = (byte)parameters.Length; + writer.WriteByte(parameterCount); + + ulong dirtyBits = forceAll ? (~0ul) : NextDirtyBits(); + writer.WriteULong(dirtyBits); + + // iterate on byte count. if it's >256, it won't break + // serialization - just not serialize excess layers. + for (int i = 0; i < parameterCount; i++) + { + if ((dirtyBits & (1ul << i)) == 0) + continue; + + AnimatorControllerParameter par = parameters[i]; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = animator.GetInteger(par.nameHash); + writer.WriteInt(newIntValue); + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = animator.GetFloat(par.nameHash); + writer.WriteFloat(newFloatValue); + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = animator.GetBool(par.nameHash); + writer.WriteBool(newBoolValue); + } + } + return dirtyBits != 0; + } + + void ReadParameters(NetworkReader reader) + { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize parameterCount to be 100% sure we deserialize correct amount of bytes. + // mismatch shows error to make this super easy to debug. + byte parameterCount = reader.ReadByte(); + if (parameterCount != parameters.Length) + { + Debug.LogError($"NetworkAnimator: serialized parameter count={parameterCount} does not match expected parameter count={parameters.Length}. Are you changing animators at runtime?", gameObject); + return; + } + + bool animatorEnabled = animator.enabled; + // need to read values from NetworkReader even if animator is disabled + ulong dirtyBits = reader.ReadULong(); + for (int i = 0; i < parameterCount; i++) + { + if ((dirtyBits & (1ul << i)) == 0) + continue; + + AnimatorControllerParameter par = parameters[i]; + if (par.type == AnimatorControllerParameterType.Int) + { + int newIntValue = reader.ReadInt(); + if (animatorEnabled) + animator.SetInteger(par.nameHash, newIntValue); + } + else if (par.type == AnimatorControllerParameterType.Float) + { + float newFloatValue = reader.ReadFloat(); + if (animatorEnabled) + animator.SetFloat(par.nameHash, newFloatValue); + } + else if (par.type == AnimatorControllerParameterType.Bool) + { + bool newBoolValue = reader.ReadBool(); + if (animatorEnabled) + animator.SetBool(par.nameHash, newBoolValue); + } + } + } + + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + base.OnSerialize(writer, initialState); + if (initialState) + { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize layerCount to be 100% sure we deserialize correct amount of bytes. + // (255 layers should be enough for everyone, write it as byte) + byte layerCount = (byte)animator.layerCount; + writer.WriteByte(layerCount); + + // iterate on byte count. if it's >256, it won't break + // serialization - just not serialize excess layers. + for (int i = 0; i < layerCount; i++) + { + AnimatorStateInfo st = animator.IsInTransition(i) + ? animator.GetNextAnimatorStateInfo(i) + : animator.GetCurrentAnimatorStateInfo(i); + writer.WriteInt(st.fullPathHash); + writer.WriteFloat(st.normalizedTime); + writer.WriteFloat(animator.GetLayerWeight(i)); + } + WriteParameters(writer, true); + } + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + base.OnDeserialize(reader, initialState); + if (initialState) + { + // fix: https://github.com/MirrorNetworking/Mirror/issues/2852 + // serialize layerCount to be 100% sure we deserialize correct amount of bytes. + // mismatch shows error to make this super easy to debug. + byte layerCount = reader.ReadByte(); + if (layerCount != animator.layerCount) + { + Debug.LogError($"NetworkAnimator: serialized layer count={layerCount} does not match expected layer count={animator.layerCount}. Are you changing animators at runtime?", gameObject); + return; + } + + for (int i = 0; i < layerCount; i++) + { + int stateHash = reader.ReadInt(); + float normalizedTime = reader.ReadFloat(); + float weight = reader.ReadFloat(); + + animator.SetLayerWeight(i, weight); + animator.Play(stateHash, i, normalizedTime); + } + + ReadParameters(reader); + } + } + + /// + /// Causes an animation trigger to be invoked for a networked object. + /// If local authority is set, and this is called from the client, then the trigger will be invoked on the server and all clients. If not, then this is called on the server, and the trigger will be called on all clients. + /// + /// Name of trigger. + public void SetTrigger(string triggerName) + { + SetTrigger(Animator.StringToHash(triggerName)); + } + + /// + /// Causes an animation trigger to be invoked for a networked object. + /// + /// Hash id of trigger (from the Animator). + public void SetTrigger(int hash) + { + if (clientAuthority) + { + if (!isClient) + { + Debug.LogWarning("Tried to set animation in the server for a client-controlled animator", gameObject); + return; + } + + if (!isOwned) + { + Debug.LogWarning("Only the client with authority can set animations", gameObject); + return; + } + + if (isClient) + CmdOnAnimationTriggerServerMessage(hash); + + // call on client right away + HandleAnimTriggerMsg(hash); + } + else + { + if (!isServer) + { + Debug.LogWarning("Tried to set animation in the client for a server-controlled animator", gameObject); + return; + } + + HandleAnimTriggerMsg(hash); + RpcOnAnimationTriggerClientMessage(hash); + } + } + + /// + /// Causes an animation trigger to be reset for a networked object. + /// If local authority is set, and this is called from the client, then the trigger will be reset on the server and all clients. If not, then this is called on the server, and the trigger will be reset on all clients. + /// + /// Name of trigger. + public void ResetTrigger(string triggerName) + { + ResetTrigger(Animator.StringToHash(triggerName)); + } + + /// Causes an animation trigger to be reset for a networked object. + /// Hash id of trigger (from the Animator). + public void ResetTrigger(int hash) + { + if (clientAuthority) + { + if (!isClient) + { + Debug.LogWarning("Tried to reset animation in the server for a client-controlled animator", gameObject); + return; + } + + if (!isOwned) + { + Debug.LogWarning("Only the client with authority can reset animations", gameObject); + return; + } + + if (isClient) + CmdOnAnimationResetTriggerServerMessage(hash); + + // call on client right away + HandleAnimResetTriggerMsg(hash); + } + else + { + if (!isServer) + { + Debug.LogWarning("Tried to reset animation in the client for a server-controlled animator", gameObject); + return; + } + + HandleAnimResetTriggerMsg(hash); + RpcOnAnimationResetTriggerClientMessage(hash); + } + } + + #region server message handlers + + [Command] + void CmdOnAnimationServerMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + //Debug.Log($"OnAnimationMessage for netId {netId}"); + + // handle and broadcast + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(parameters)) + { + HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); + RpcOnAnimationClientMessage(stateHash, normalizedTime, layerId, weight, parameters); + } + } + + [Command] + void CmdOnAnimationParametersServerMessage(byte[] parameters) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(parameters)) + { + HandleAnimParamsMsg(networkReader); + RpcOnAnimationParametersClientMessage(parameters); + } + } + + [Command] + void CmdOnAnimationTriggerServerMessage(int hash) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + // host should have already the trigger + bool isHostOwner = isClient && isOwned; + if (!isHostOwner) + { + HandleAnimTriggerMsg(hash); + } + + RpcOnAnimationTriggerClientMessage(hash); + } + + [Command] + void CmdOnAnimationResetTriggerServerMessage(int hash) + { + // Ignore messages from client if not in client authority mode + if (!clientAuthority) + return; + + // handle and broadcast + // host should have already the trigger + bool isHostOwner = isClient && isOwned; + if (!isHostOwner) + { + HandleAnimResetTriggerMsg(hash); + } + + RpcOnAnimationResetTriggerClientMessage(hash); + } + + [Command] + void CmdSetAnimatorSpeed(float newSpeed) + { + // set animator + animator.speed = newSpeed; + animatorSpeed = newSpeed; + } + + #endregion + + #region client message handlers + + [ClientRpc] + void RpcOnAnimationClientMessage(int stateHash, float normalizedTime, int layerId, float weight, byte[] parameters) + { + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(parameters)) + HandleAnimMsg(stateHash, normalizedTime, layerId, weight, networkReader); + } + + [ClientRpc] + void RpcOnAnimationParametersClientMessage(byte[] parameters) + { + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(parameters)) + HandleAnimParamsMsg(networkReader); + } + + [ClientRpc(includeOwner = false)] + void RpcOnAnimationTriggerClientMessage(int hash) + { + // already handled on server in SetTrigger + // or CmdOnAnimationTriggerServerMessage + if (!isServer) + HandleAnimTriggerMsg(hash); + } + + [ClientRpc(includeOwner = false)] + void RpcOnAnimationResetTriggerClientMessage(int hash) + { + // already handled on server in ResetTrigger + // or CmdOnAnimationResetTriggerServerMessage + if (!isServer) + HandleAnimResetTriggerMsg(hash); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/NetworkAnimator.cs.meta b/Assets/Mirror/Components/NetworkAnimator.cs.meta new file mode 100644 index 0000000..2e48ed4 --- /dev/null +++ b/Assets/Mirror/Components/NetworkAnimator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7f6f3bf89aa97405989c802ba270f815 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkAnimator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs new file mode 100644 index 0000000..d3c3632 --- /dev/null +++ b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Diagnostics Debugger")] + public class NetworkDiagnosticsDebugger : MonoBehaviour + { + public bool logInMessages = true; + public bool logOutMessages = true; + void OnInMessage(NetworkDiagnostics.MessageInfo msgInfo) + { + if (logInMessages) + Debug.Log(msgInfo); + } + void OnOutMessage(NetworkDiagnostics.MessageInfo msgInfo) + { + if (logOutMessages) + Debug.Log(msgInfo); + } + void OnEnable() + { + NetworkDiagnostics.InMessageEvent += OnInMessage; + NetworkDiagnostics.OutMessageEvent += OnOutMessage; + } + void OnDisable() + { + NetworkDiagnostics.InMessageEvent -= OnInMessage; + NetworkDiagnostics.OutMessageEvent -= OnOutMessage; + } + } +} diff --git a/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta new file mode 100644 index 0000000..04e4335 --- /dev/null +++ b/Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: bc9f0a0fe4124424b8f9d4927795ee01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkDiagnosticsDebugger.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs b/Assets/Mirror/Components/NetworkLobbyManager.cs new file mode 100644 index 0000000..3dcd4ea --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyManager.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// This is a specialized NetworkManager that includes a networked lobby. + /// + /// + /// The lobby has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkLobbyPlayer component be on the lobby player objects. + /// NetworkLobbyManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkLobbyManager, there are new virtual functions on the NetworkLobbyManager that begin with "OnLobby". These should be used on classes derived from NetworkLobbyManager instead of the virtual functions on NetworkManager. + /// The OnLobby*() functions have empty implementations on the NetworkLobbyManager base class, so the base class functions do not have to be called. + /// + [AddComponentMenu("Network/Network Lobby Manager")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-manager")] + [Obsolete("Use / inherit from NetworkRoomManager instead")] + public class NetworkLobbyManager : NetworkRoomManager {} +} diff --git a/Assets/Mirror/Components/NetworkLobbyManager.cs.meta b/Assets/Mirror/Components/NetworkLobbyManager.cs.meta new file mode 100644 index 0000000..5e4ca94 --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a4c96e6dd99826849ab1431f94547141 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkLobbyManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs b/Assets/Mirror/Components/NetworkLobbyPlayer.cs new file mode 100644 index 0000000..95ffbbc --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyPlayer.cs @@ -0,0 +1,15 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// This component works in conjunction with the NetworkLobbyManager to make up the multiplayer lobby system. + /// The LobbyPrefab object of the NetworkLobbyManager must have this component on it. This component holds basic lobby player data required for the lobby to function. Game specific data for lobby players can be put in other components on the LobbyPrefab or in scripts derived from NetworkLobbyPlayer. + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Lobby Player")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-player")] + [Obsolete("Use / inherit from NetworkRoomPlayer instead")] + public class NetworkLobbyPlayer : NetworkRoomPlayer {} +} diff --git a/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta b/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta new file mode 100644 index 0000000..23ce3a4 --- /dev/null +++ b/Assets/Mirror/Components/NetworkLobbyPlayer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 777a368af85f2e84da7ea5666581921b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkLobbyPlayer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs b/Assets/Mirror/Components/NetworkPingDisplay.cs new file mode 100644 index 0000000..255e62d --- /dev/null +++ b/Assets/Mirror/Components/NetworkPingDisplay.cs @@ -0,0 +1,39 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// Component that will display the clients ping in milliseconds + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Ping Display")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-ping-display")] + public class NetworkPingDisplay : MonoBehaviour + { + public Color color = Color.white; + public int padding = 2; + public int width = 150; + public int height = 25; + + void OnGUI() + { + // only while client is active + if (!NetworkClient.active) return; + + // show stats in bottom right corner, right aligned + GUI.color = color; + Rect rect = new Rect(Screen.width - width - padding, Screen.height - height - padding, width, height); + GUILayout.BeginArea(rect); + GUIStyle style = GUI.skin.GetStyle("Label"); + style.alignment = TextAnchor.MiddleRight; + GUILayout.BeginHorizontal(style); + GUILayout.Label($"RTT: {Math.Round(NetworkTime.rtt * 1000)}ms"); + GUI.color = NetworkClient.connectionQuality.ColorCode(); + GUILayout.Label($"Q: {new string('-', (int)NetworkClient.connectionQuality)}"); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + GUI.color = Color.white; + } + } +} diff --git a/Assets/Mirror/Components/NetworkPingDisplay.cs.meta b/Assets/Mirror/Components/NetworkPingDisplay.cs.meta new file mode 100644 index 0000000..c141614 --- /dev/null +++ b/Assets/Mirror/Components/NetworkPingDisplay.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: bc654f29862fc2643b948f772ebb9e68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkPingDisplay.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRigidbody.meta b/Assets/Mirror/Components/NetworkRigidbody.meta new file mode 100644 index 0000000..ce84fee --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80106690aef541a5b8e2f8fb3d5949ad +timeCreated: 1686733778 diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs new file mode 100644 index 0000000..a88341a --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs @@ -0,0 +1,115 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody (Reliable)")] + public class NetworkRigidbodyReliable : NetworkTransformReliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody rb; + bool wasKinematic; + + protected override void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + } + } + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta new file mode 100644 index 0000000..0ebea63 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cb803efbe62c34d7baece46c9ffebad9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs new file mode 100644 index 0000000..9872ccc --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs @@ -0,0 +1,135 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody 2D (Reliable)")] + public class NetworkRigidbodyReliable2D : NetworkTransformReliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody2D rb; + bool wasKinematic; + + protected override void OnValidate() + { + if (Application.isPlaying) return; + + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + } + } + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + return; + } +#if UNITY_6000_0_OR_NEWER + wasKinematic = rb.bodyType.HasFlag(RigidbodyType2D.Kinematic); +#else + wasKinematic = rb.isKinematic; +#endif + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. +#if UNITY_6000_0_OR_NEWER + public override void OnStopServer() => rb.bodyType = wasKinematic ? RigidbodyType2D.Kinematic : RigidbodyType2D.Dynamic; + public override void OnStopClient() => rb.bodyType = wasKinematic ? RigidbodyType2D.Kinematic : RigidbodyType2D.Dynamic; +#else + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; +#endif + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation.eulerAngles.z; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta new file mode 100644 index 0000000..c02ae5d --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7ec4f7556ca1e4b55a3381fc6a02b1bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyReliable2D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs new file mode 100644 index 0000000..e2a34c0 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs @@ -0,0 +1,115 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody (Unreliable)")] + public class NetworkRigidbodyUnreliable : NetworkTransformUnreliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody rb; + bool wasKinematic; + + protected override void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + } + } + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody.target {target.name} is missing a Rigidbody", this); + return; + } + wasKinematic = rb.isKinematic; + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; + + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. + if (!owned) rb.isKinematic = true; + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta new file mode 100644 index 0000000..646d27c --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3b20dc110904e47f8a154cdcf6433eae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs new file mode 100644 index 0000000..6c021f0 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs @@ -0,0 +1,136 @@ +using UnityEngine; + +namespace Mirror +{ + // [RequireComponent(typeof(Rigidbody))] <- OnValidate ensures this is on .target + [AddComponentMenu("Network/Network Rigidbody 2D (Unreliable)")] + public class NetworkRigidbodyUnreliable2D : NetworkTransformUnreliable + { + bool clientAuthority => syncDirection == SyncDirection.ClientToServer; + + Rigidbody2D rb; + bool wasKinematic; + + protected override void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + base.OnValidate(); + + // we can't overwrite .target to be a Rigidbody. + // but we can ensure that .target has a Rigidbody, and use it. + if (target.GetComponent() == null) + { + Debug.LogWarning($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + } + } + + // cach Rigidbody and original isKinematic setting + protected override void Awake() + { + // we can't overwrite .target to be a Rigidbody. + // but we can use its Rigidbody component. + rb = target.GetComponent(); + if (rb == null) + { + Debug.LogError($"{name}'s NetworkRigidbody2D.target {target.name} is missing a Rigidbody2D", this); + return; + } + +#if UNITY_6000_0_OR_NEWER + wasKinematic = rb.bodyType.HasFlag(RigidbodyType2D.Kinematic); +#else + wasKinematic = rb.isKinematic; +#endif + base.Awake(); + } + + // reset forced isKinematic flag to original. + // otherwise the overwritten value would remain between sessions forever. + // for example, a game may run as client, set rigidbody.iskinematic=true, + // then run as server, where .iskinematic isn't touched and remains at + // the overwritten=true, even though the user set it to false originally. +#if UNITY_6000_0_OR_NEWER + public override void OnStopServer() => rb.bodyType = wasKinematic ? RigidbodyType2D.Kinematic : RigidbodyType2D.Dynamic; + public override void OnStopClient() => rb.bodyType = wasKinematic ? RigidbodyType2D.Kinematic : RigidbodyType2D.Dynamic; +#else + public override void OnStopServer() => rb.isKinematic = wasKinematic; + public override void OnStopClient() => rb.isKinematic = wasKinematic; +#endif + // overwriting Construct() and Apply() to set Rigidbody.MovePosition + // would give more jittery movement. + + // FixedUpdate for physics + void FixedUpdate() + { + // who ever has authority moves the Rigidbody with physics. + // everyone else simply sets it to kinematic. + // so that only the Transform component is synced. + + // host mode + if (isServer && isClient) + { + // in host mode, we own it it if: + // clientAuthority is disabled (hence server / we own it) + // clientAuthority is enabled and we have authority over this object. + bool owned = !clientAuthority || IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + // client only + else if (isClient) + { + // on the client, we own it only if clientAuthority is enabled, + // and we have authority over this object. + bool owned = IsClientWithAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + // server only + else if (isServer) + { + // on the server, we always own it if clientAuthority is disabled. + bool owned = !clientAuthority; + + // only set to kinematic if we don't own it + // otherwise don't touch isKinematic. + // the authority owner might use it either way. +#if UNITY_6000_0_OR_NEWER + if (!owned) rb.bodyType = RigidbodyType2D.Kinematic; +#else + if (!owned) rb.isKinematic = true; +#endif + } + } + + protected override void OnTeleport(Vector3 destination) + { + base.OnTeleport(destination); + + rb.position = transform.position; + } + + protected override void OnTeleport(Vector3 destination, Quaternion rotation) + { + base.OnTeleport(destination, rotation); + + rb.position = transform.position; + rb.rotation = transform.rotation.eulerAngles.z; + } + } +} diff --git a/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta new file mode 100644 index 0000000..99239af --- /dev/null +++ b/Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1c7e12ad9b9ae443c9fdf37e9f5ecd36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRigidbody/NetworkRigidbodyUnreliable2D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs b/Assets/Mirror/Components/NetworkRoomManager.cs new file mode 100644 index 0000000..698b190 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomManager.cs @@ -0,0 +1,683 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.Serialization; + +namespace Mirror +{ + /// + /// This is a specialized NetworkManager that includes a networked room. + /// + /// + /// The room has slots that track the joined players, and a maximum player count that is enforced. It requires that the NetworkRoomPlayer component be on the room player objects. + /// NetworkRoomManager is derived from NetworkManager, and so it implements many of the virtual functions provided by the NetworkManager class. To avoid accidentally replacing functionality of the NetworkRoomManager, there are new virtual functions on the NetworkRoomManager that begin with "OnRoom". These should be used on classes derived from NetworkRoomManager instead of the virtual functions on NetworkManager. + /// The OnRoom*() functions have empty implementations on the NetworkRoomManager base class, so the base class functions do not have to be called. + /// + [AddComponentMenu("Network/Network Room Manager")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-manager")] + public class NetworkRoomManager : NetworkManager + { + public struct PendingPlayer + { + public NetworkConnectionToClient conn; + public GameObject roomPlayer; + } + + [Header("Room Settings")] + [FormerlySerializedAs("m_ShowRoomGUI")] + [SerializeField] + [Tooltip("This flag controls whether the default UI is shown for the room")] + public bool showRoomGUI = true; + + [FormerlySerializedAs("m_MinPlayers")] + [SerializeField] + [Tooltip("Minimum number of players to auto-start the game")] + public int minPlayers = 1; + + [FormerlySerializedAs("m_RoomPlayerPrefab")] + [SerializeField] + [Tooltip("Prefab to use for the Room Player")] + public NetworkRoomPlayer roomPlayerPrefab; + + /// + /// The scene to use for the room. This is similar to the offlineScene of the NetworkManager. + /// + [Scene] + public string RoomScene; + + /// + /// The scene to use for the playing the game from the room. This is similar to the onlineScene of the NetworkManager. + /// + [Scene] + public string GameplayScene; + + /// + /// List of players that are in the Room + /// + [FormerlySerializedAs("m_PendingPlayers")] + public HashSet pendingPlayers = new HashSet(); + + [Header("Diagnostics")] + /// + /// True when all players have submitted a Ready message + /// + [Tooltip("Diagnostic flag indicating all players are ready to play")] + [FormerlySerializedAs("allPlayersReady")] + [ReadOnly, SerializeField] bool _allPlayersReady; + + /// + /// These slots track players that enter the room. + /// The slotId on players is global to the game - across all players. + /// + [ReadOnly, Tooltip("List of Room Player objects")] + public HashSet roomSlots = new HashSet(); + + public bool allPlayersReady + { + get => _allPlayersReady; + set + { + bool wasReady = _allPlayersReady; + bool nowReady = value; + + if (wasReady != nowReady) + { + _allPlayersReady = value; + + if (nowReady) + { + OnRoomServerPlayersReady(); + } + else + { + OnRoomServerPlayersNotReady(); + } + } + } + } + + public override void OnValidate() + { + base.OnValidate(); + + // always <= maxConnections + minPlayers = Mathf.Min(minPlayers, maxConnections); + + // always >= 0 + minPlayers = Mathf.Max(minPlayers, 0); + + if (roomPlayerPrefab != null) + { + NetworkIdentity identity = roomPlayerPrefab.GetComponent(); + if (identity == null) + { + roomPlayerPrefab = null; + Debug.LogError("RoomPlayer prefab must have a NetworkIdentity component."); + } + } + } + + void SceneLoadedForPlayer(NetworkConnectionToClient conn, GameObject roomPlayer) + { + //Debug.Log($"NetworkRoom SceneLoadedForPlayer scene: {SceneManager.GetActiveScene().path} {conn}"); + + if (Utils.IsSceneActive(RoomScene)) + { + // cant be ready in room, add to ready list + PendingPlayer pending; + pending.conn = conn; + pending.roomPlayer = roomPlayer; + pendingPlayers.Add(pending); + return; + } + + GameObject gamePlayer = OnRoomServerCreateGamePlayer(conn, roomPlayer); + if (gamePlayer == null) + { + // get start position from base class + Transform startPos = GetStartPosition(); + gamePlayer = startPos != null + ? Instantiate(playerPrefab, startPos.position, startPos.rotation) + : Instantiate(playerPrefab, Vector3.zero, Quaternion.identity); + } + + if (!OnRoomServerSceneLoadedForPlayer(conn, roomPlayer, gamePlayer)) + return; + + // replace room player with game player + NetworkServer.ReplacePlayerForConnection(conn, gamePlayer, ReplacePlayerOptions.KeepAuthority); + } + + internal void CallOnClientEnterRoom() + { + OnRoomClientEnter(); + foreach (NetworkRoomPlayer player in roomSlots) + if (player != null) + { + player.OnClientEnterRoom(); + } + } + + internal void CallOnClientExitRoom() + { + OnRoomClientExit(); + foreach (NetworkRoomPlayer player in roomSlots) + if (player != null) + { + player.OnClientExitRoom(); + } + } + + /// + /// CheckReadyToBegin checks all of the players in the room to see if their readyToBegin flag is set. + /// If all of the players are ready, then the server switches from the RoomScene to the PlayScene, essentially starting the game. This is called automatically in response to NetworkRoomPlayer.CmdChangeReadyState. + /// + public void CheckReadyToBegin() + { + if (!Utils.IsSceneActive(RoomScene)) + return; + + int numberOfReadyPlayers = NetworkServer.connections.Count(conn => + conn.Value != null && + conn.Value.identity != null && + conn.Value.identity.TryGetComponent(out NetworkRoomPlayer nrp) && + nrp.readyToBegin); + + bool enoughReadyPlayers = minPlayers <= 0 || numberOfReadyPlayers >= minPlayers; + if (enoughReadyPlayers) + { + pendingPlayers.Clear(); + allPlayersReady = true; + } + else + allPlayersReady = false; + } + + #region server handlers + + /// + /// Called on the server when a new client connects. + /// Unity calls this on the Server when a Client connects to the Server. Use an override to tell the NetworkManager what to do when a client connects to the server. + /// + /// Connection from client. + public override void OnServerConnect(NetworkConnectionToClient conn) + { + // cannot join game in progress + if (!Utils.IsSceneActive(RoomScene)) + { + Debug.Log($"Not in Room scene...disconnecting {conn}"); + conn.Disconnect(); + return; + } + + base.OnServerConnect(conn); + OnRoomServerConnect(conn); + } + + /// + /// Called on the server when a client disconnects. + /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. + /// + /// Connection from client. + public override void OnServerDisconnect(NetworkConnectionToClient conn) + { + if (conn.identity != null) + { + NetworkRoomPlayer roomPlayer = conn.identity.GetComponent(); + + if (roomPlayer != null) + roomSlots.Remove(roomPlayer); + + foreach (NetworkIdentity clientOwnedObject in conn.owned) + { + roomPlayer = clientOwnedObject.GetComponent(); + if (roomPlayer != null) + roomSlots.Remove(roomPlayer); + } + } + + allPlayersReady = false; + + foreach (NetworkRoomPlayer player in roomSlots) + { + if (player != null) + player.GetComponent().readyToBegin = false; + } + + if (Utils.IsSceneActive(RoomScene)) + RecalculateRoomPlayerIndices(); + + OnRoomServerDisconnect(conn); + base.OnServerDisconnect(conn); + + // Restart the server if we're headless and no players are connected. + // This will send server to offline scene, where auto-start will run. + if (Utils.IsHeadless() && numPlayers < 1) + StopServer(); + } + + // Sequential index used in round-robin deployment of players into instances and score positioning + public int clientIndex; + + /// + /// Called on the server when a client is ready. + /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. + /// + /// Connection from client. + public override void OnServerReady(NetworkConnectionToClient conn) + { + //Debug.Log($"NetworkRoomManager OnServerReady {conn}"); + base.OnServerReady(conn); + + if (conn != null && conn.identity != null) + { + GameObject roomPlayer = conn.identity.gameObject; + + // if null or not a room player, don't replace it + if (roomPlayer != null && roomPlayer.GetComponent() != null) + SceneLoadedForPlayer(conn, roomPlayer); + } + } + + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnectionToClient conn) + { + // increment the index before adding the player, so first player starts at 1 + clientIndex++; + + if (Utils.IsSceneActive(RoomScene)) + { + allPlayersReady = false; + + //Debug.Log("NetworkRoomManager.OnServerAddPlayer playerPrefab: {roomPlayerPrefab.name}"); + + GameObject newRoomGameObject = OnRoomServerCreateRoomPlayer(conn); + if (newRoomGameObject == null) + newRoomGameObject = Instantiate(roomPlayerPrefab.gameObject, Vector3.zero, Quaternion.identity); + + NetworkServer.AddPlayerForConnection(conn, newRoomGameObject); + } + else + { + // Late joiners not supported...should've been kicked by OnServerDisconnect + Debug.Log($"Not in Room scene...disconnecting {conn}"); + conn.Disconnect(); + } + } + + [Server] + public void RecalculateRoomPlayerIndices() + { + if (roomSlots.Count > 0) + { + int i = 0; + foreach (NetworkRoomPlayer player in roomSlots) + player.index = i++; + } + } + + /// + /// This causes the server to switch scenes and sets the networkSceneName. + /// Clients that connect to this server will automatically switch to this scene. This is called automatically if onlineScene or offlineScene are set, but it can be called from user code to switch scenes again while the game is in progress. This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready() again to participate in the new scene. + /// + /// + public override void ServerChangeScene(string newSceneName) + { + if (newSceneName == RoomScene) + { + foreach (NetworkRoomPlayer roomPlayer in roomSlots) + { + if (roomPlayer == null) + continue; + + // find the game-player object for this connection, and destroy it + NetworkIdentity identity = roomPlayer.GetComponent(); + + if (NetworkServer.active) + { + // re-add the room object + roomPlayer.GetComponent().readyToBegin = false; + NetworkServer.ReplacePlayerForConnection(identity.connectionToClient, roomPlayer.gameObject, ReplacePlayerOptions.KeepAuthority); + } + } + + allPlayersReady = false; + } + + base.ServerChangeScene(newSceneName); + } + + /// + /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). + /// + /// The name of the new scene. + public override void OnServerSceneChanged(string sceneName) + { + if (sceneName != RoomScene) + { + // call SceneLoadedForPlayer on any players that become ready while we were loading the scene. + foreach (PendingPlayer pending in pendingPlayers) + SceneLoadedForPlayer(pending.conn, pending.roomPlayer); + + pendingPlayers.Clear(); + } + + OnRoomServerSceneChanged(sceneName); + } + + /// + /// This is invoked when a server is started - including when a host is started. + /// StartServer has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartServer() + { + if (string.IsNullOrWhiteSpace(RoomScene)) + { + Debug.LogError("NetworkRoomManager RoomScene is empty. Set the RoomScene in the inspector for the NetworkRoomManager"); + return; + } + + if (string.IsNullOrWhiteSpace(GameplayScene)) + { + Debug.LogError("NetworkRoomManager PlayScene is empty. Set the PlayScene in the inspector for the NetworkRoomManager"); + return; + } + + OnRoomStartServer(); + } + + /// + /// This is invoked when a host is started. + /// StartHost has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartHost() + { + OnRoomStartHost(); + } + + /// + /// This is called when a server is stopped - including when a host is stopped. + /// + public override void OnStopServer() + { + roomSlots.Clear(); + OnRoomStopServer(); + } + + /// + /// This is called when a host is stopped. + /// + public override void OnStopHost() + { + OnRoomStopHost(); + } + + #endregion + + #region client handlers + + /// + /// This is invoked when the client is started. + /// + public override void OnStartClient() + { + if (roomPlayerPrefab == null || roomPlayerPrefab.gameObject == null) + Debug.LogError("NetworkRoomManager no RoomPlayer prefab is registered. Please add a RoomPlayer prefab."); + else + NetworkClient.RegisterPrefab(roomPlayerPrefab.gameObject); + + if (playerPrefab == null) + Debug.LogError("NetworkRoomManager no GamePlayer prefab is registered. Please add a GamePlayer prefab."); + + OnRoomStartClient(); + } + + /// + /// Called on the client when connected to a server. + /// The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects. + /// + public override void OnClientConnect() + { + OnRoomClientConnect(); + base.OnClientConnect(); + } + + /// + /// Called on clients when disconnected from a server. + /// This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects. + /// + public override void OnClientDisconnect() + { + OnRoomClientDisconnect(); + base.OnClientDisconnect(); + } + + /// + /// This is called when a client is stopped. + /// + public override void OnStopClient() + { + OnRoomStopClient(); + CallOnClientExitRoom(); + roomSlots.Clear(); + } + + /// + /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. + /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. + /// + public override void OnClientSceneChanged() + { + if (Utils.IsSceneActive(RoomScene)) + { + if (NetworkClient.isConnected) + CallOnClientEnterRoom(); + } + else + CallOnClientExitRoom(); + + base.OnClientSceneChanged(); + OnRoomClientSceneChanged(); + } + + #endregion + + #region room server virtuals + + /// + /// This is called on the host when a host is started. + /// + public virtual void OnRoomStartHost() {} + + /// + /// This is called on the host when the host is stopped. + /// + public virtual void OnRoomStopHost() {} + + /// + /// This is called on the server when the server is started - including when a host is started. + /// + public virtual void OnRoomStartServer() {} + + /// + /// This is called on the server when the server is started - including when a host is stopped. + /// + public virtual void OnRoomStopServer() {} + + /// + /// This is called on the server when a new client connects to the server. + /// + /// The new connection. + public virtual void OnRoomServerConnect(NetworkConnectionToClient conn) {} + + /// + /// This is called on the server when a client disconnects. + /// + /// The connection that disconnected. + public virtual void OnRoomServerDisconnect(NetworkConnectionToClient conn) {} + + /// + /// This is called on the server when a networked scene finishes loading. + /// + /// Name of the new scene. + public virtual void OnRoomServerSceneChanged(string sceneName) {} + + /// + /// This allows customization of the creation of the room-player object on the server. + /// By default the roomPlayerPrefab is used to create the room-player, but this function allows that behaviour to be customized. + /// + /// The connection the player object is for. + /// The new room-player object. + public virtual GameObject OnRoomServerCreateRoomPlayer(NetworkConnectionToClient conn) + { + return null; + } + + /// + /// This allows customization of the creation of the GamePlayer object on the server. + /// By default the gamePlayerPrefab is used to create the game-player, but this function allows that behaviour to be customized. The object returned from the function will be used to replace the room-player on the connection. + /// + /// The connection the player object is for. + /// The room player object for this connection. + /// A new GamePlayer object. + public virtual GameObject OnRoomServerCreateGamePlayer(NetworkConnectionToClient conn, GameObject roomPlayer) + { + return null; + } + + /// + /// This allows customization of the creation of the GamePlayer object on the server. + /// This is only called for subsequent GamePlay scenes after the first one. + /// See OnRoomServerCreateGamePlayer(NetworkConnection, GameObject) to customize the player object for the initial GamePlay scene. + /// + /// The connection the player object is for. + public virtual void OnRoomServerAddPlayer(NetworkConnectionToClient conn) + { + base.OnServerAddPlayer(conn); + } + + // for users to apply settings from their room player object to their in-game player object + /// + /// This is called on the server when it is told that a client has finished switching from the room scene to a game player scene. + /// When switching from the room, the room-player is replaced with a game-player object. This callback function gives an opportunity to apply state from the room-player to the game-player object. + /// + /// The connection of the player + /// The room player object. + /// The game player object. + /// False to not allow this player to replace the room player. + public virtual bool OnRoomServerSceneLoadedForPlayer(NetworkConnectionToClient conn, GameObject roomPlayer, GameObject gamePlayer) + { + return true; + } + + /// + /// This is called on server from NetworkRoomPlayer.CmdChangeReadyState when client indicates change in Ready status. + /// + public virtual void ReadyStatusChanged() + { + int CurrentPlayers = 0; + int ReadyPlayers = 0; + + foreach (NetworkRoomPlayer item in roomSlots) + { + if (item != null) + { + CurrentPlayers++; + if (item.readyToBegin) + ReadyPlayers++; + } + } + + if (CurrentPlayers == ReadyPlayers) + CheckReadyToBegin(); + else + allPlayersReady = false; + } + + /// + /// This is called on the server when all the players in the room are ready. + /// The default implementation of this function uses ServerChangeScene() to switch to the game player scene. By implementing this callback you can customize what happens when all the players in the room are ready, such as adding a countdown or a confirmation for a group leader. + /// + public virtual void OnRoomServerPlayersReady() + { + // all players are readyToBegin, start the game + ServerChangeScene(GameplayScene); + } + + /// + /// This is called on the server when CheckReadyToBegin finds that players are not ready + /// May be called multiple times while not ready players are joining + /// + public virtual void OnRoomServerPlayersNotReady() {} + + #endregion + + #region room client virtuals + + /// + /// This is a hook to allow custom behaviour when the game client enters the room. + /// + public virtual void OnRoomClientEnter() {} + + /// + /// This is a hook to allow custom behaviour when the game client exits the room. + /// + public virtual void OnRoomClientExit() {} + + /// + /// This is called on the client when it connects to server. + /// + public virtual void OnRoomClientConnect() {} + + /// + /// This is called on the client when disconnected from a server. + /// + public virtual void OnRoomClientDisconnect() {} + + /// + /// This is called on the client when a client is started. + /// + public virtual void OnRoomStartClient() {} + + /// + /// This is called on the client when the client stops. + /// + public virtual void OnRoomStopClient() {} + + /// + /// This is called on the client when the client is finished loading a new networked scene. + /// + public virtual void OnRoomClientSceneChanged() {} + + #endregion + + #region optional UI + + /// + /// virtual so inheriting classes can roll their own + /// + public virtual void OnGUI() + { + if (!showRoomGUI) + return; + + if (NetworkServer.active && Utils.IsSceneActive(GameplayScene)) + { + GUILayout.BeginArea(new Rect(Screen.width - 150f, 10f, 140f, 30f)); + if (GUILayout.Button("Return to Room")) + ServerChangeScene(RoomScene); + GUILayout.EndArea(); + } + + if (Utils.IsSceneActive(RoomScene)) + GUI.Box(new Rect(10f, 180f, 520f, 150f), "PLAYERS"); + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/NetworkRoomManager.cs.meta b/Assets/Mirror/Components/NetworkRoomManager.cs.meta new file mode 100644 index 0000000..744bcdc --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 615e6c6589cf9e54cad646b5a11e0529 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRoomManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs b/Assets/Mirror/Components/NetworkRoomPlayer.cs new file mode 100644 index 0000000..6b7cda4 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomPlayer.cs @@ -0,0 +1,195 @@ +using UnityEngine; + +namespace Mirror +{ + /// + /// This component works in conjunction with the NetworkRoomManager to make up the multiplayer room system. + /// The RoomPrefab object of the NetworkRoomManager must have this component on it. This component holds basic room player data required for the room to function. Game specific data for room players can be put in other components on the RoomPrefab or in scripts derived from NetworkRoomPlayer. + /// + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Room Player")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-room-player")] + public class NetworkRoomPlayer : NetworkBehaviour + { + /// + /// This flag controls whether the default UI is shown for the room player. + /// As this UI is rendered using the old GUI system, it is only recommended for testing purposes. + /// + [Tooltip("This flag controls whether the default UI is shown for the room player")] + public bool showRoomGUI = true; + + [Header("Diagnostics")] + + /// + /// Diagnostic flag indicating whether this player is ready for the game to begin. + /// Invoke CmdChangeReadyState method on the client to set this flag. + /// When all players are ready to begin, the game will start. This should not be set directly, CmdChangeReadyState should be called on the client to set it on the server. + /// + [ReadOnly, Tooltip("Diagnostic flag indicating whether this player is ready for the game to begin")] + [SyncVar(hook = nameof(ReadyStateChanged))] + public bool readyToBegin; + + /// + /// Diagnostic index of the player, e.g. Player1, Player2, etc. + /// + [ReadOnly, Tooltip("Diagnostic index of the player, e.g. Player1, Player2, etc.")] + [SyncVar(hook = nameof(IndexChanged))] + public int index; + + #region Unity Callbacks + + /// + /// Do not use Start - Override OnStartHost / OnStartClient instead! + /// + public virtual void Start() + { + if (NetworkManager.singleton is NetworkRoomManager room) + { + // NetworkRoomPlayer object must be set to DontDestroyOnLoad along with NetworkRoomManager + // in server and all clients, otherwise it will be respawned in the game scene which would + // have undesirable effects. + if (room.dontDestroyOnLoad) + DontDestroyOnLoad(gameObject); + + room.roomSlots.Add(this); + + if (NetworkServer.active) + room.RecalculateRoomPlayerIndices(); + + if (NetworkClient.active) + room.CallOnClientEnterRoom(); + } + else Debug.LogError("RoomPlayer could not find a NetworkRoomManager. The RoomPlayer requires a NetworkRoomManager object to function. Make sure that there is one in the scene."); + } + + public virtual void OnDisable() + { + if (NetworkClient.active && NetworkManager.singleton is NetworkRoomManager room) + { + // only need to call this on client as server removes it before object is destroyed + room.roomSlots.Remove(this); + + room.CallOnClientExitRoom(); + } + } + + #endregion + + #region Commands + + [Command] + public void CmdChangeReadyState(bool readyState) + { + readyToBegin = readyState; + NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; + if (room != null) + { + room.ReadyStatusChanged(); + } + } + + #endregion + + #region SyncVar Hooks + + /// + /// This is a hook that is invoked on clients when the index changes. + /// + /// The old index value + /// The new index value + public virtual void IndexChanged(int oldIndex, int newIndex) {} + + /// + /// This is a hook that is invoked on clients when a RoomPlayer switches between ready or not ready. + /// This function is called when the a client player calls CmdChangeReadyState. + /// + /// New Ready State + public virtual void ReadyStateChanged(bool oldReadyState, bool newReadyState) {} + + #endregion + + #region Room Client Virtuals + + /// + /// This is a hook that is invoked on clients for all room player objects when entering the room. + /// Note: isLocalPlayer is not guaranteed to be set until OnStartLocalPlayer is called. + /// + public virtual void OnClientEnterRoom() {} + + /// + /// This is a hook that is invoked on clients for all room player objects when exiting the room. + /// + public virtual void OnClientExitRoom() {} + + #endregion + + #region Optional UI + + /// + /// Render a UI for the room. Override to provide your own UI + /// + public virtual void OnGUI() + { + if (!showRoomGUI) + return; + + NetworkRoomManager room = NetworkManager.singleton as NetworkRoomManager; + if (room) + { + if (!room.showRoomGUI) + return; + + if (!Utils.IsSceneActive(room.RoomScene)) + return; + + DrawPlayerReadyState(); + DrawPlayerReadyButton(); + } + } + + void DrawPlayerReadyState() + { + GUILayout.BeginArea(new Rect(20f + (index * 100), 200f, 90f, 130f)); + + GUILayout.Label($"Player [{index + 1}]"); + + if (readyToBegin) + GUILayout.Label("Ready"); + else + GUILayout.Label("Not Ready"); + + if (((isServer && index > 0) || isServerOnly) && GUILayout.Button("REMOVE")) + { + // This button only shows on the Host for all players other than the Host + // Host and Players can't remove themselves (stop the client instead) + // Host can kick a Player this way. + GetComponent().connectionToClient.Disconnect(); + } + + GUILayout.EndArea(); + } + + void DrawPlayerReadyButton() + { + if (NetworkClient.active && isLocalPlayer) + { + GUILayout.BeginArea(new Rect(20f, 300f, 120f, 20f)); + + if (readyToBegin) + { + if (GUILayout.Button("Cancel")) + CmdChangeReadyState(false); + } + else + { + if (GUILayout.Button("Ready")) + CmdChangeReadyState(true); + } + + GUILayout.EndArea(); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta b/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta new file mode 100644 index 0000000..f9d2978 --- /dev/null +++ b/Assets/Mirror/Components/NetworkRoomPlayer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 79874ac94d5b1314788ecf0e86bd23fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkRoomPlayer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkStatistics.cs b/Assets/Mirror/Components/NetworkStatistics.cs new file mode 100644 index 0000000..c00bb19 --- /dev/null +++ b/Assets/Mirror/Components/NetworkStatistics.cs @@ -0,0 +1,194 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// Shows Network messages and bytes sent and received per second. + /// + /// + /// Add this component to the same object as Network Manager. + /// + [AddComponentMenu("Network/Network Statistics")] + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-statistics")] + public class NetworkStatistics : MonoBehaviour + { + // update interval + double intervalStartTime; + + // --------------------------------------------------------------------- + + // CLIENT (public fields for other components to grab statistics) + // long bytes to support >2GB + [HideInInspector] public int clientIntervalReceivedPackets; + [HideInInspector] public long clientIntervalReceivedBytes; + [HideInInspector] public int clientIntervalSentPackets; + [HideInInspector] public long clientIntervalSentBytes; + + // results from last interval + // long bytes to support >2GB + [HideInInspector] public int clientReceivedPacketsPerSecond; + [HideInInspector] public long clientReceivedBytesPerSecond; + [HideInInspector] public int clientSentPacketsPerSecond; + [HideInInspector] public long clientSentBytesPerSecond; + + // --------------------------------------------------------------------- + + // SERVER (public fields for other components to grab statistics) + // capture interval + // long bytes to support >2GB + [HideInInspector] public int serverIntervalReceivedPackets; + [HideInInspector] public long serverIntervalReceivedBytes; + [HideInInspector] public int serverIntervalSentPackets; + [HideInInspector] public long serverIntervalSentBytes; + + // results from last interval + // long bytes to support >2GB + [HideInInspector] public int serverReceivedPacketsPerSecond; + [HideInInspector] public long serverReceivedBytesPerSecond; + [HideInInspector] public int serverSentPacketsPerSecond; + [HideInInspector] public long serverSentBytesPerSecond; + + // NetworkManager sets Transport.active in Awake(). + // so let's hook into it in Start(). + void Start() + { + // find available transport + Transport transport = Transport.active; + if (transport != null) + { + transport.OnClientDataReceived += OnClientReceive; + transport.OnClientDataSent += OnClientSend; + transport.OnServerDataReceived += OnServerReceive; + transport.OnServerDataSent += OnServerSend; + } + else Debug.LogError($"NetworkStatistics: no available or active Transport found on this platform: {Application.platform}"); + } + + void OnDestroy() + { + // remove transport hooks + Transport transport = Transport.active; + if (transport != null) + { + transport.OnClientDataReceived -= OnClientReceive; + transport.OnClientDataSent -= OnClientSend; + transport.OnServerDataReceived -= OnServerReceive; + transport.OnServerDataSent -= OnServerSend; + } + } + + void OnClientReceive(ArraySegment data, int channelId) + { + ++clientIntervalReceivedPackets; + clientIntervalReceivedBytes += data.Count; + } + + void OnClientSend(ArraySegment data, int channelId) + { + ++clientIntervalSentPackets; + clientIntervalSentBytes += data.Count; + } + + void OnServerReceive(int connectionId, ArraySegment data, int channelId) + { + ++serverIntervalReceivedPackets; + serverIntervalReceivedBytes += data.Count; + } + + void OnServerSend(int connectionId, ArraySegment data, int channelId) + { + ++serverIntervalSentPackets; + serverIntervalSentBytes += data.Count; + } + + void Update() + { + // calculate results every second + if (NetworkTime.localTime >= intervalStartTime + 1) + { + if (NetworkClient.active) UpdateClient(); + if (NetworkServer.active) UpdateServer(); + + intervalStartTime = NetworkTime.localTime; + } + } + + void UpdateClient() + { + clientReceivedPacketsPerSecond = clientIntervalReceivedPackets; + clientReceivedBytesPerSecond = clientIntervalReceivedBytes; + clientSentPacketsPerSecond = clientIntervalSentPackets; + clientSentBytesPerSecond = clientIntervalSentBytes; + + clientIntervalReceivedPackets = 0; + clientIntervalReceivedBytes = 0; + clientIntervalSentPackets = 0; + clientIntervalSentBytes = 0; + } + + void UpdateServer() + { + serverReceivedPacketsPerSecond = serverIntervalReceivedPackets; + serverReceivedBytesPerSecond = serverIntervalReceivedBytes; + serverSentPacketsPerSecond = serverIntervalSentPackets; + serverSentBytesPerSecond = serverIntervalSentBytes; + + serverIntervalReceivedPackets = 0; + serverIntervalReceivedBytes = 0; + serverIntervalSentPackets = 0; + serverIntervalSentBytes = 0; + } + + void OnGUI() + { + // only show if either server or client active + if (NetworkClient.active || NetworkServer.active) + { + // create main GUI area + // 120 is below NetworkManager HUD in all cases. + GUILayout.BeginArea(new Rect(10, 120, 215, 300)); + + // show client / server stats if active + if (NetworkClient.active) OnClientGUI(); + if (NetworkServer.active) OnServerGUI(); + + // end of GUI area + GUILayout.EndArea(); + } + } + + void OnClientGUI() + { + // background + GUILayout.BeginVertical("Box"); + GUILayout.Label("Client Statistics"); + + // sending ("msgs" instead of "packets" to fit larger numbers) + GUILayout.Label($"Send: {clientSentPacketsPerSecond} msgs @ {Utils.PrettyBytes(clientSentBytesPerSecond)}/s"); + + // receiving ("msgs" instead of "packets" to fit larger numbers) + GUILayout.Label($"Recv: {clientReceivedPacketsPerSecond} msgs @ {Utils.PrettyBytes(clientReceivedBytesPerSecond)}/s"); + + // end background + GUILayout.EndVertical(); + } + + void OnServerGUI() + { + // background + GUILayout.BeginVertical("Box"); + GUILayout.Label("Server Statistics"); + + // sending ("msgs" instead of "packets" to fit larger numbers) + GUILayout.Label($"Send: {serverSentPacketsPerSecond} msgs @ {Utils.PrettyBytes(serverSentBytesPerSecond)}/s"); + + // receiving ("msgs" instead of "packets" to fit larger numbers) + GUILayout.Label($"Recv: {serverReceivedPacketsPerSecond} msgs @ {Utils.PrettyBytes(serverReceivedBytesPerSecond)}/s"); + + // end background + GUILayout.EndVertical(); + } + } +} diff --git a/Assets/Mirror/Components/NetworkStatistics.cs.meta b/Assets/Mirror/Components/NetworkStatistics.cs.meta new file mode 100644 index 0000000..ccce31f --- /dev/null +++ b/Assets/Mirror/Components/NetworkStatistics.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6d7da4e566d24ea7b0e12178d934b648 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkStatistics.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform.meta b/Assets/Mirror/Components/NetworkTransform.meta new file mode 100644 index 0000000..255a0fa --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 36de72d9255741659bcbd1971ed29822 +timeCreated: 1668358590 diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs new file mode 100644 index 0000000..0d6c9ed --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs @@ -0,0 +1,547 @@ +// Snapshot Interpolation: https://gafferongames.com/post/snapshot_interpolation/ +// +// Base class for NetworkTransform and NetworkTransformChild. +// => simple unreliable sync without any interpolation for now. +// => which means we don't need teleport detection either +// +// NOTE: several functions are virtual in case someone needs to modify a part. +// +// Channel: uses UNRELIABLE at all times. +// -> out of order packets are dropped automatically +// -> it's better than RELIABLE for several reasons: +// * head of line blocking would add delay +// * resending is mostly pointless +// * bigger data race: +// -> if we use a Cmd() at position X over reliable +// -> client gets Cmd() and X at the same time, but buffers X for bufferTime +// -> for unreliable, it would get X before the reliable Cmd(), still +// buffer for bufferTime but end up closer to the original time +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public enum CoordinateSpace { Local, World } + + public abstract class NetworkTransformBase : NetworkBehaviour + { + // target transform to sync. can be on a child. + // TODO this field is kind of unnecessary since we now support child NetworkBehaviours + [Header("Target")] + [Tooltip("The Transform component to sync. May be on on this GameObject, or on a child.")] + public Transform target; + + // Is this a client with authority over this transform? + // This component could be on the player object or any object that has been assigned authority to this client. + protected bool IsClientWithAuthority => isClient && authority; + + // snapshots with initial capacity to avoid early resizing & allocations: see NetworkRigidbodyBenchmark example. + public readonly SortedList clientSnapshots = new SortedList(16); + public readonly SortedList serverSnapshots = new SortedList(16); + + // selective sync ////////////////////////////////////////////////////// + [Header("Selective Sync\nDon't change these at Runtime")] + public bool syncPosition = true; // do not change at runtime! + public bool syncRotation = true; // do not change at runtime! + public bool syncScale = false; // do not change at runtime! rare. off by default. + + [Header("Bandwidth Savings")] + [Tooltip("When true, changes are not sent unless greater than sensitivity values below.")] + public bool onlySyncOnChange = true; + [Tooltip("Apply smallest-three quaternion compression. This is lossy, you can disable it if the small rotation inaccuracies are noticeable in your project.")] + public bool compressRotation = true; + + // interpolation is on by default, but can be disabled to jump to + // the destination immediately. some projects need this. + [Header("Interpolation")] + [Tooltip("Set to false to have a snap-like effect on position movement.")] + public bool interpolatePosition = true; + [Tooltip("Set to false to have a snap-like effect on rotations.")] + public bool interpolateRotation = true; + [Tooltip("Set to false to remove scale smoothing. Example use-case: Instant flipping of sprites that use -X and +X for direction.")] + public bool interpolateScale = true; + + // CoordinateSpace /////////////////////////////////////////////////////////// + [Header("Coordinate Space")] + [Tooltip("Local by default. World may be better when changing hierarchy, or non-NetworkTransforms root position/rotation/scale values.")] + public CoordinateSpace coordinateSpace = CoordinateSpace.Local; + + // convert syncInterval to sendIntervalMultiplier. + // in the future this can be moved into core to support tick aligned Sync, + public uint sendIntervalMultiplier + { + get + { + if (syncInterval > 0) + { + // if syncInterval is > 0, calculate how many multiples of NetworkManager.sendRate it is + // + // for example: + // NetworkServer.sendInterval is 1/60 = 0.16 + // NetworkTransform.syncInterval is 0.5 (500ms). + // 0.5 / 0.16 = 3.125 + // in other words: 3.125 x sendInterval + // + // note that NetworkServer.sendInterval is usually set on start. + // to make this work in Edit mode, make sure that NetworkManager + // OnValidate sets NetworkServer.sendInterval immediately. + float multiples = syncInterval / NetworkServer.sendInterval; + + // syncInterval is always supposed to sync at a minimum of 1 x sendInterval. + // that's what we do for every other NetworkBehaviour since + // we only sync in Broadcast() which is called @ sendInterval. + return multiples > 1 ? (uint)Mathf.RoundToInt(multiples) : 1; + } + + // if syncInterval is 0, use NetworkManager.sendRate (x1) + return 1; + } + } + + [Header("Timeline Offset")] + [Tooltip("Add a small timeline offset to account for decoupled arrival of NetworkTime and NetworkTransform snapshots.\nfixes: https://github.com/MirrorNetworking/Mirror/issues/3427")] + public bool timelineOffset = true; + + // Ninja's Notes on offset & mulitplier: + // + // In a no multiplier scenario: + // 1. Snapshots are sent every frame (frame being 1 NM send interval). + // 2. Time Interpolation is set to be 'behind' by 2 frames times. + // In theory where everything works, we probably have around 2 snapshots before we need to interpolate snapshots. From NT perspective, we should always have around 2 snapshots ready, so no stutter. + // + // In a multiplier scenario: + // 1. Snapshots are sent every 10 frames. + // 2. Time Interpolation remains 'behind by 2 frames'. + // When everything works, we are receiving NT snapshots every 10 frames, but start interpolating after 2. + // Even if I assume we had 2 snapshots to begin with to start interpolating (which we don't), by the time we reach 13th frame, we are out of snapshots, and have to wait 7 frames for next snapshot to come. This is the reason why we absolutely need the timestamp adjustment. We are starting way too early to interpolate. + // + protected double timeStampAdjustment => NetworkServer.sendInterval * (sendIntervalMultiplier - 1); + protected double offset => timelineOffset ? NetworkServer.sendInterval * sendIntervalMultiplier : 0; + + // velocity for convenience (animators etc.) + // this isn't technically NetworkTransforms job, but it's needed by so many projects that we just provide it anyway. + public Vector3 velocity { get; private set; } + public Vector3 angularVelocity { get; private set; } + + // debugging /////////////////////////////////////////////////////////// + [Header("Debug")] + public bool showGizmos; + public bool showOverlay; + public Color overlayColor = new Color(0, 0, 0, 0.5f); + + protected override void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + base.OnValidate(); + + // configure in awake + Configure(); + } + + // initialization ////////////////////////////////////////////////////// + // forcec configuration of some settings + protected virtual void Configure() + { + // set target to self if none yet + if (target == null) target = transform; + + // Unity doesn't support setting world scale. + // OnValidate force disables syncScale in world mode. + if (coordinateSpace == CoordinateSpace.World) syncScale = false; + } + + // make sure to call this when inheriting too! + protected virtual void Awake() + { + // sometimes OnValidate() doesn't run before launching a project. + // need to guarantee configuration runs. + Configure(); + } + + // snapshot functions ////////////////////////////////////////////////// + // get local/world position + protected virtual Vector3 GetPosition() => + coordinateSpace == CoordinateSpace.Local ? target.localPosition : target.position; + + // get local/world rotation + protected virtual Quaternion GetRotation() => + coordinateSpace == CoordinateSpace.Local ? target.localRotation : target.rotation; + + // get local/world scale + protected virtual Vector3 GetScale() => + coordinateSpace == CoordinateSpace.Local ? target.localScale : target.lossyScale; + + // set local/world position + protected virtual void SetPosition(Vector3 position) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localPosition = position; + else + target.position = position; + } + + // set local/world rotation + protected virtual void SetRotation(Quaternion rotation) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localRotation = rotation; + else + target.rotation = rotation; + } + + // set local/world position + protected virtual void SetScale(Vector3 scale) + { + if (coordinateSpace == CoordinateSpace.Local) + target.localScale = scale; + // Unity doesn't support setting world scale. + // OnValidate disables syncScale in world mode. + // else + // target.lossyScale = scale; // TODO + } + + // construct a snapshot of the current state + // => internal for testing + protected virtual TransformSnapshot Construct() + { + // NetworkTime.localTime for double precision until Unity has it too + return new TransformSnapshot( + // our local time is what the other end uses as remote time + NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet + 0, // the other end fills out local time itself + GetPosition(), + GetRotation(), + GetScale() + ); + } + + protected void AddSnapshot(SortedList snapshots, double timeStamp, Vector3? position, Quaternion? rotation, Vector3? scale) + { + // position, rotation, scale can have no value if same as last time. + // saves bandwidth. + // but we still need to feed it to snapshot interpolation. we can't + // just have gaps in there if nothing has changed. for example, if + // client sends snapshot at t=0 + // client sends nothing for 10s because not moved + // client sends snapshot at t=10 + // then the server would assume that it's one super slow move and + // replay it for 10 seconds. + + if (!position.HasValue) position = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position : GetPosition(); + if (!rotation.HasValue) rotation = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation(); + if (!scale.HasValue) scale = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale(); + + // insert transform snapshot + SnapshotInterpolation.InsertIfNotExists( + snapshots, + NetworkClient.snapshotSettings.bufferLimit, + new TransformSnapshot( + timeStamp, // arrival remote timestamp. NOT remote time. + NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet + position.Value, + rotation.Value, + scale.Value + ) + ); + } + + // apply a snapshot to the Transform. + // -> start, end, interpolated are all passed in caes they are needed + // -> a regular game would apply the 'interpolated' snapshot + // -> a board game might want to jump to 'goal' directly + // (it's easier to always interpolate and then apply selectively, + // instead of manually interpolating x, y, z, ... depending on flags) + // => internal for testing + // + // NOTE: stuck detection is unnecessary here. + // we always set transform.position anyway, we can't get stuck. + protected virtual void Apply(TransformSnapshot interpolated, TransformSnapshot endGoal) + { + // local position/rotation for VR support + // + // if syncPosition/Rotation/Scale is disabled then we received nulls + // -> current position/rotation/scale would've been added as snapshot + // -> we still interpolated + // -> but simply don't apply it. if the user doesn't want to sync + // scale, then we should not touch scale etc. + + // calculate the velocity and angular velocity for the object + // these can be used to drive animations or other behaviours + if (!isOwned && Time.deltaTime > 0) + { + velocity = (transform.localPosition - interpolated.position) / Time.deltaTime; + angularVelocity = (transform.localRotation.eulerAngles - interpolated.rotation.eulerAngles) / Time.deltaTime; + } + + // interpolate parts + if (syncPosition) SetPosition(interpolatePosition ? interpolated.position : endGoal.position); + if (syncRotation) SetRotation(interpolateRotation ? interpolated.rotation : endGoal.rotation); + if (syncScale) SetScale(interpolateScale ? interpolated.scale : endGoal.scale); + } + + // client->server teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [Command] + public void CmdTeleport(Vector3 destination) + { + // client can only teleport objects that it has authority over. + if (syncDirection != SyncDirection.ClientToServer) return; + + // TODO what about host mode? + OnTeleport(destination); + + // if a client teleports, we need to broadcast to everyone else too + // TODO the teleported client should ignore the rpc though. + // otherwise if it already moved again after teleporting, + // the rpc would come a little bit later and reset it once. + // TODO or not? if client ONLY calls Teleport(pos), the position + // would only be set after the rpc. unless the client calls + // BOTH Teleport(pos) and target.position=pos + RpcTeleport(destination); + } + + // client->server teleport to force position and rotation without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [Command] + public void CmdTeleport(Vector3 destination, Quaternion rotation) + { + // client can only teleport objects that it has authority over. + if (syncDirection != SyncDirection.ClientToServer) return; + + // TODO what about host mode? + OnTeleport(destination, rotation); + + // if a client teleports, we need to broadcast to everyone else too + // TODO the teleported client should ignore the rpc though. + // otherwise if it already moved again after teleporting, + // the rpc would come a little bit later and reset it once. + // TODO or not? if client ONLY calls Teleport(pos), the position + // would only be set after the rpc. unless the client calls + // BOTH Teleport(pos) and target.position=pos + RpcTeleport(destination, rotation); + } + + // server->client teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [ClientRpc] + public void RpcTeleport(Vector3 destination) + { + // NOTE: even in client authority mode, the server is always allowed + // to teleport the player. for example: + // * CmdEnterPortal() might teleport the player + // * Some people use client authority with server sided checks + // so the server should be able to reset position if needed. + + // TODO what about host mode? + OnTeleport(destination); + } + + // server->client teleport to force position and rotation without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [ClientRpc] + public void RpcTeleport(Vector3 destination, Quaternion rotation) + { + // NOTE: even in client authority mode, the server is always allowed + // to teleport the player. for example: + // * CmdEnterPortal() might teleport the player + // * Some people use client authority with server sided checks + // so the server should be able to reset position if needed. + + // TODO what about host mode? + OnTeleport(destination, rotation); + } + + // teleport on server, broadcast to clients. + [Server] + public void ServerTeleport(Vector3 destination, Quaternion rotation) + { + OnTeleport(destination, rotation); + RpcTeleport(destination, rotation); + } + + [ClientRpc] + void RpcResetState() + { + ResetState(); + } + + // common Teleport code for client->server and server->client + protected virtual void OnTeleport(Vector3 destination) + { + // set the new position. + // interpolation will automatically continue. + target.position = destination; + + // reset interpolation to immediately jump to the new position. + // do not call Reset() here, this would cause delta compression to + // get out of sync for NetworkTransformReliable because NTReliable's + // 'override Reset()' resets lastDe/SerializedPosition: + // https://github.com/MirrorNetworking/Mirror/issues/3588 + // because client's next OnSerialize() will delta compress, + // but server's last delta will have been reset, causing offsets. + // + // instead, simply clear snapshots. + ResetState(); + + // TODO + // what if we still receive a snapshot from before the interpolation? + // it could easily happen over unreliable. + // -> maybe add destination as first entry? + } + + // common Teleport code for client->server and server->client + protected virtual void OnTeleport(Vector3 destination, Quaternion rotation) + { + // set the new position. + // interpolation will automatically continue. + target.position = destination; + target.rotation = rotation; + + // reset interpolation to immediately jump to the new position. + // do not call Reset() here, this would cause delta compression to + // get out of sync for NetworkTransformReliable because NTReliable's + // 'override Reset()' resets lastDe/SerializedPosition: + // https://github.com/MirrorNetworking/Mirror/issues/3588 + // because client's next OnSerialize() will delta compress, + // but server's last delta will have been reset, causing offsets. + // + // instead, simply clear snapshots. + ResetState(); + + // TODO + // what if we still receive a snapshot from before the interpolation? + // it could easily happen over unreliable. + // -> maybe add destination as first entry? + } + + public virtual void ResetState() + { + // disabled objects aren't updated anymore. + // so let's clear the buffers. + serverSnapshots.Clear(); + clientSnapshots.Clear(); + + // Prevent resistance from CharacterController + // or non-knematic Rigidbodies when teleporting. + Physics.SyncTransforms(); + } + + public virtual void Reset() + { + ResetState(); + // default to ClientToServer so this works immediately for users + syncDirection = SyncDirection.ClientToServer; + } + + protected virtual void OnEnable() + { + ResetState(); + + if (NetworkServer.active) + NetworkIdentity.clientAuthorityCallback += OnClientAuthorityChanged; + } + + protected virtual void OnDisable() + { + ResetState(); + + if (NetworkServer.active) + NetworkIdentity.clientAuthorityCallback -= OnClientAuthorityChanged; + } + + [ServerCallback] + void OnClientAuthorityChanged(NetworkConnectionToClient conn, NetworkIdentity identity, bool authorityState) + { + if (identity != netIdentity) return; + + // If server gets authority or syncdirection is server to client, + // we don't reset buffers. + // This is because if syncdirection is S to C, we will never have + // snapshot issues since there is only ever 1 source. + + if (syncDirection == SyncDirection.ClientToServer) + { + ResetState(); + RpcResetState(); + } + } + + // OnGUI allocates even if it does nothing. avoid in release. +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // debug /////////////////////////////////////////////////////////////// + protected virtual void OnGUI() + { + if (!showOverlay) return; + if (!Camera.main) return; + + // show data next to player for easier debugging. this is very useful! + // IMPORTANT: this is basically an ESP hack for shooter games. + // DO NOT make this available with a hotkey in release builds + if (!Debug.isDebugBuild) return; + + // project position to screen + Vector3 point = Camera.main.WorldToScreenPoint(target.position); + + // enough alpha, in front of camera and in screen? + if (point.z >= 0 && Utils.IsPointInScreen(point)) + { + GUI.color = overlayColor; + GUILayout.BeginArea(new Rect(point.x, Screen.height - point.y, 200, 100)); + + // always show both client & server buffers so it's super + // obvious if we accidentally populate both. + GUILayout.Label($"Server Buffer:{serverSnapshots.Count}"); + GUILayout.Label($"Client Buffer:{clientSnapshots.Count}"); + + GUILayout.EndArea(); + GUI.color = Color.white; + } + } + + protected virtual void DrawGizmos(SortedList buffer) + { + // only draw if we have at least two entries + if (buffer.Count < 2) return; + + // calculate threshold for 'old enough' snapshots + double threshold = NetworkTime.localTime - NetworkClient.bufferTime; + Color oldEnoughColor = new Color(0, 1, 0, 0.5f); + Color notOldEnoughColor = new Color(0.5f, 0.5f, 0.5f, 0.3f); + + // draw the whole buffer for easier debugging. + // it's worth seeing how much we have buffered ahead already + for (int i = 0; i < buffer.Count; ++i) + { + // color depends on if old enough or not + TransformSnapshot entry = buffer.Values[i]; + bool oldEnough = entry.localTime <= threshold; + Gizmos.color = oldEnough ? oldEnoughColor : notOldEnoughColor; + Gizmos.DrawWireCube(entry.position, Vector3.one); + } + + // extra: lines between start<->position<->goal + Gizmos.color = Color.green; + Gizmos.DrawLine(buffer.Values[0].position, target.position); + Gizmos.color = Color.white; + Gizmos.DrawLine(target.position, buffer.Values[1].position); + } + + protected virtual void OnDrawGizmos() + { + // This fires in edit mode but that spams NRE's so check isPlaying + if (!Application.isPlaying) return; + if (!showGizmos) return; + + if (isServer) DrawGizmos(serverSnapshots); + if (isClient) DrawGizmos(clientSnapshots); + } +#endif + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta new file mode 100644 index 0000000..bc6aac2 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7c44135fde488424eaf28566206ce473 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/NetworkTransformBase.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs new file mode 100644 index 0000000..a231b88 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs @@ -0,0 +1,717 @@ +// Quake NetworkTransform based on 2022 NetworkTransformUnreliable. +// Snapshot Interpolation: https://gafferongames.com/post/snapshot_interpolation/ +// Quake: https://www.jfedor.org/quake3/ +// +// Base class for NetworkTransform and NetworkTransformChild. +// => simple unreliable sync without any interpolation for now. +// => which means we don't need teleport detection either +// +// several functions are virtual in case someone needs to modify a part. +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Transform Hybrid")] + public class NetworkTransformHybrid : NetworkBehaviourHybrid + { + public bool useFixedUpdate; + TransformSnapshot? pendingSnapshot; + + // target transform to sync. can be on a child. + [Header("Target")] + [Tooltip("The Transform component to sync. May be on this GameObject, or on a child.")] + public Transform target; + + [Tooltip("Buffer size limit to avoid ever growing list memory consumption attacks.")] + public int bufferSizeLimit = 64; + internal SortedList clientSnapshots = new SortedList(); + internal SortedList serverSnapshots = new SortedList(); + + // CUSTOM CHANGE: bring back sendRate. this will probably be ported to Mirror. + // TODO but use built in syncInterval instead of the extra field here! + [Header("Synchronization")] + [Tooltip("Send N snapshots per second. Multiples of frame rate make sense.")] + public int sendRate = 30; // in Hz. easier to work with as int for EMA. easier to display '30' than '0.333333333' + public float sendInterval => 1f / sendRate; + // END CUSTOM CHANGE + + // delta compression needs to remember 'last' to compress against. + // this is from reliable full state serializations, not from last + // unreliable delta since that isn't guaranteed to be delivered. + Vector3 lastSerializedBaselinePosition = Vector3.zero; + Quaternion lastSerializedBaselineRotation = Quaternion.identity; + Vector3 lastSerializedBaselineScale = Vector3.one; + + // save last deserialized baseline to delta decompress against + Vector3 lastDeserializedBaselinePosition = Vector3.zero; // unused, but keep for delta + Quaternion lastDeserializedBaselineRotation = Quaternion.identity; // unused, but keep for delta + Vector3 lastDeserializedBaselineScale = Vector3.one; // unused, but keep for delta + + // sensitivity is for changed-detection, + // this is != precision, which is for quantization and delta compression. + [Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] + public float positionSensitivity = 0.01f; + public float rotationSensitivity = 0.01f; + public float scaleSensitivity = 0.01f; + + // selective sync ////////////////////////////////////////////////////// + [Header("Selective Sync & interpolation")] + public bool syncPosition = true; + public bool syncRotation = true; + public bool syncScale = false; + + // velocity for convenience (animators etc.) + // this isn't technically NetworkTransforms job, but it's needed by so many projects that we just provide it anyway. + public Vector3 velocity { get; private set; } + public Vector3 angularVelocity { get; private set; } + + // debugging /////////////////////////////////////////////////////////// + [Header("Debug")] + public bool debugDraw; + public bool showGizmos; + public bool showOverlay; + public Color overlayColor = new Color(0, 0, 0, 0.5f); + + // initialization ////////////////////////////////////////////////////// + // make sure to call this when inheriting too! + protected virtual void Awake() {} + + protected override void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + base.OnValidate(); + Reset(); + } + + void Reset() + { + // set target to self if none yet + if (target == null) target = transform; + + // we use sendRate for convenience. + // but project it to syncInterval for NetworkTransformHybrid to work properly. + syncInterval = sendInterval; + + // default to ClientToServer so this works immediately for users + syncDirection = SyncDirection.ClientToServer; + } + + // apply a snapshot to the Transform. + // -> start, end, interpolated are all passed in caes they are needed + // -> a regular game would apply the 'interpolated' snapshot + // -> a board game might want to jump to 'goal' directly + // (it's easier to always interpolate and then apply selectively, + // instead of manually interpolating x, y, z, ... depending on flags) + // => internal for testing + // + // NOTE: stuck detection is unnecessary here. + // we always set transform.position anyway, we can't get stuck. + protected virtual void ApplySnapshot(TransformSnapshot interpolated) + { + // local position/rotation for VR support + // + // if syncPosition/Rotation/Scale is disabled then we received nulls + // -> current position/rotation/scale would've been added as snapshot + // -> we still interpolated + // -> but simply don't apply it. if the user doesn't want to sync + // scale, then we should not touch scale etc. + + // calculate the velocity and angular velocity for the object + // these can be used to drive animations or other behaviours + if (!isOwned && Time.deltaTime > 0) + { + velocity = (transform.localPosition - interpolated.position) / Time.deltaTime; + angularVelocity = (transform.localRotation.eulerAngles - interpolated.rotation.eulerAngles) / Time.deltaTime; + } + + if (syncPosition) target.localPosition = interpolated.position; + if (syncRotation) target.localRotation = interpolated.rotation; + if (syncScale) target.localScale = interpolated.scale; + } + + // store state after baseline sync + protected override void StoreState() + { + target.GetLocalPositionAndRotation(out lastSerializedBaselinePosition, out lastSerializedBaselineRotation); + lastSerializedBaselineScale = target.localScale; + } + + // check if position / rotation / scale changed since last _full reliable_ sync. + // squared comparisons for performance + protected override bool StateChanged() + { + target.GetLocalPositionAndRotation(out Vector3 position, out Quaternion rotation); + Vector3 scale = target.localScale; + + if (syncPosition) + { + float positionDelta = Vector3.Distance(position, lastSerializedBaselinePosition); + if (positionDelta >= positionSensitivity) + { + return true; + } + } + + if (syncRotation) + { + float rotationDelta = Quaternion.Angle(lastSerializedBaselineRotation, rotation); + if (rotationDelta >= rotationSensitivity) + { + return true; + } + } + + if (syncScale) + { + float scaleDelta = Vector3.Distance(scale, lastSerializedBaselineScale); + if (scaleDelta >= scaleSensitivity) + { + return true; + } + } + + return false; + } + + // serialization /////////////////////////////////////////////////////// + // called on server and on client, depending on SyncDirection + protected override void OnSerializeBaseline(NetworkWriter writer) + { + // perf: get position/rotation directly. TransformSnapshot is too expensive. + // TransformSnapshot snapshot = ConstructSnapshot(); + target.GetLocalPositionAndRotation(out Vector3 position, out Quaternion rotation); + Vector3 scale = target.localScale; + + if (syncPosition) writer.WriteVector3(position); + if (syncRotation) writer.WriteQuaternion(rotation); + if (syncScale) writer.WriteVector3(scale); + } + + // called on server and on client, depending on SyncDirection + protected override void OnDeserializeBaseline(NetworkReader reader, byte baselineTick) + { + // deserialize + Vector3? position = null; + Quaternion? rotation = null; + Vector3? scale = null; + + if (syncPosition) + { + position = reader.ReadVector3(); + lastDeserializedBaselinePosition = position.Value; + } + if (syncRotation) + { + rotation = reader.ReadQuaternion(); + lastDeserializedBaselineRotation = rotation.Value; + } + if (syncScale) + { + scale = reader.ReadVector3(); + lastDeserializedBaselineScale = scale.Value; + } + + // debug draw: baseline = yellow + if (debugDraw && position.HasValue) Debug.DrawLine(position.Value, position.Value + Vector3.up, Color.yellow, 10f); + + // if baseline counts as delta, insert it into snapshot buffer too + if (baselineIsDelta) + { + if (isServer) + { + OnClientToServerDeltaSync(position, rotation, scale); + } + else if (isClient) + { + OnServerToClientDeltaSync(position, rotation, scale); + } + } + } + + // called on server and on client, depending on SyncDirection + protected override void OnSerializeDelta(NetworkWriter writer) + { + // perf: get position/rotation directly. TransformSnapshot is too expensive. + // TransformSnapshot snapshot = ConstructSnapshot(); + target.GetLocalPositionAndRotation(out Vector3 position, out Quaternion rotation); + Vector3 scale = target.localScale; + + if (syncPosition) writer.WriteVector3(position); + if (syncRotation) writer.WriteQuaternion(rotation); + if (syncScale) writer.WriteVector3(scale); + } + + // called on server and on client, depending on SyncDirection + protected override void OnDeserializeDelta(NetworkReader reader, byte baselineTick) + { + Vector3? position = null; + Quaternion? rotation = null; + Vector3? scale = null; + + if (syncPosition) position = reader.ReadVector3(); + if (syncRotation) rotation = reader.ReadQuaternion(); + if (syncScale) scale = reader.ReadVector3(); + + // debug draw: delta = white + if (debugDraw && position.HasValue) Debug.DrawLine(position.Value, position.Value + Vector3.up, Color.white, 10f); + + if (isServer) + { + OnClientToServerDeltaSync(position, rotation, scale); + } + else if (isClient) + { + OnServerToClientDeltaSync(position, rotation, scale); + } + } + + // processing ////////////////////////////////////////////////////////// + // local authority client sends sync message to server for broadcasting + protected virtual void OnClientToServerDeltaSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // only apply if in client authority mode + if (syncDirection != SyncDirection.ClientToServer) return; + + // protect against ever-growing buffer size attacks + if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; + + // only player owned objects (with a connection) can send to + // server. we can get the timestamp from the connection. + double timestamp = connectionToClient.remoteTimeStamp; + + // insert transform snapshot + SnapshotInterpolation.InsertIfNotExists( + serverSnapshots, + bufferSizeLimit, + new TransformSnapshot( + timestamp, // arrival remote timestamp. NOT remote time. + NetworkTime.localTime, // Unity 2019 doesn't have Time.timeAsDouble yet + position.HasValue ? position.Value : Vector3.zero, + rotation.HasValue ? rotation.Value : Quaternion.identity, + scale.HasValue ? scale.Value : Vector3.one + )); + } + + // server broadcasts sync message to all clients + protected virtual void OnServerToClientDeltaSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // in host mode, the server sends rpcs to all clients. + // the host client itself will receive them too. + // -> host server is always the source of truth + // -> we can ignore any rpc on the host client + // => otherwise host objects would have ever growing clientBuffers + // (rpc goes to clients. if isServer is true too then we are host) + if (isServer) return; + + // don't apply for local player with authority + if (IsClientWithAuthority) return; + + // Debug.Log($"[{name}] Client: received delta for baseline #{baselineTick}"); + + // on the client, we receive rpcs for all entities. + // not all of them have a connectionToServer. + // but all of them go through NetworkClient.connection. + // we can get the timestamp from there. + double timestamp = NetworkClient.connection.remoteTimeStamp; + + // position, rotation, scale can have no value if same as last time. + // saves bandwidth. + // but we still need to feed it to snapshot interpolation. we can't + // just have gaps in there if nothing has changed. for example, if + // client sends snapshot at t=0 + // client sends nothing for 10s because not moved + // client sends snapshot at t=10 + // then the server would assume that it's one super slow move and + // replay it for 10 seconds. + // if (!syncPosition) position = clientSnapshots.Count > 0 ? clientSnapshots.Values[clientSnapshots.Count - 1].position : target.localPosition; + // if (!syncRotation) rotation = clientSnapshots.Count > 0 ? clientSnapshots.Values[clientSnapshots.Count - 1].rotation : target.localRotation; + // if (!syncScale) scale = clientSnapshots.Count > 0 ? clientSnapshots.Values[clientSnapshots.Count - 1].scale : target.localScale; + + // insert snapshot + SnapshotInterpolation.InsertIfNotExists( + clientSnapshots, + bufferSizeLimit, + new TransformSnapshot( + timestamp, // arrival remote timestamp. NOT remote time. + NetworkTime.localTime, // Unity 2019 doesn't have Time.timeAsDouble yet + position.HasValue ? position.Value : Vector3.zero, + rotation.HasValue ? rotation.Value : Quaternion.identity, + scale.HasValue ? scale.Value : Vector3.one + )); + } + + // update server /////////////////////////////////////////////////////// + void UpdateServerInterpolation() + { + // apply buffered snapshots IF client authority + // -> in server authority, server moves the object + // so no need to apply any snapshots there. + // -> don't apply for host mode player objects either, even if in + // client authority mode. if it doesn't go over the network, + // then we don't need to do anything. + if (syncDirection == SyncDirection.ClientToServer && !isOwned) + { + if (serverSnapshots.Count > 0) + { + // step the transform interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + serverSnapshots, + // CUSTOM CHANGE: allow for custom sendRate+sendInterval again. + // for example, if the object is moving @ 1 Hz, always put it back by 1s. + // that's how we still get smooth movement even with a global timeline. + connectionToClient.remoteTimeline - sendInterval, + // END CUSTOM CHANGE + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + if (useFixedUpdate) + pendingSnapshot = computed; + else + ApplySnapshot(computed); + } + } + } + + // update client /////////////////////////////////////////////////////// + void UpdateClientInterpolation() + { + // only while we have snapshots + if (clientSnapshots.Count > 0) + { + // step the interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + clientSnapshots, + // CUSTOM CHANGE: allow for custom sendRate+sendInterval again. + // for example, if the object is moving @ 1 Hz, always put it back by 1s. + // that's how we still get smooth movement even with a global timeline. + NetworkTime.time - sendInterval, // == NetworkClient.localTimeline from snapshot interpolation + // END CUSTOM CHANGE + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + if (useFixedUpdate) + pendingSnapshot = computed; + else + ApplySnapshot(computed); + } + } + + // Update() without LateUpdate() split: otherwise perf. is cut in half! + protected override void Update() + { + base.Update(); // NetworkBehaviourHybrid + + if (isServer) + { + // interpolate remote clients + UpdateServerInterpolation(); + } + // 'else if' because host mode shouldn't update both. + else if (isClient) + { + // interpolate remote client (and local player if no authority) + if (!IsClientWithAuthority) UpdateClientInterpolation(); + } + } + + void FixedUpdate() + { + if (!useFixedUpdate) return; + + if (pendingSnapshot.HasValue) + { + ApplySnapshot(pendingSnapshot.Value); + pendingSnapshot = null; + } + } + + // common Teleport code for client->server and server->client + protected virtual void OnTeleport(Vector3 destination) + { + // reset any in-progress interpolation & buffers + ResetState(); + + // set the new position. + // interpolation will automatically continue. + target.position = destination; + + // TODO + // what if we still receive a snapshot from before the interpolation? + // it could easily happen over unreliable. + // -> maybe add destination as first entry? + } + + // common Teleport code for client->server and server->client + protected virtual void OnTeleport(Vector3 destination, Quaternion rotation) + { + // reset any in-progress interpolation & buffers + ResetState(); + + // set the new position. + // interpolation will automatically continue. + target.position = destination; + target.rotation = rotation; + + // TODO + // what if we still receive a snapshot from before the interpolation? + // it could easily happen over unreliable. + // -> maybe add destination as first entry? + } + + // server->client teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [ClientRpc] + public void RpcTeleport(Vector3 destination) + { + // NOTE: even in client authority mode, the server is always allowed + // to teleport the player. for example: + // * CmdEnterPortal() might teleport the player + // * Some people use client authority with server sided checks + // so the server should be able to reset position if needed. + + // TODO what about host mode? + OnTeleport(destination); + } + + // server->client teleport to force position and rotation without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [ClientRpc] + public void RpcTeleport(Vector3 destination, Quaternion rotation) + { + // NOTE: even in client authority mode, the server is always allowed + // to teleport the player. for example: + // * CmdEnterPortal() might teleport the player + // * Some people use client authority with server sided checks + // so the server should be able to reset position if needed. + + // TODO what about host mode? + OnTeleport(destination, rotation); + } + + // client->server teleport to force position without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [Command] + public void CmdTeleport(Vector3 destination) + { + // client can only teleport objects that it has authority over. + if (syncDirection != SyncDirection.ClientToServer) return; + + // TODO what about host mode? + OnTeleport(destination); + + // if a client teleports, we need to broadcast to everyone else too + // TODO the teleported client should ignore the rpc though. + // otherwise if it already moved again after teleporting, + // the rpc would come a little bit later and reset it once. + // TODO or not? if client ONLY calls Teleport(pos), the position + // would only be set after the rpc. unless the client calls + // BOTH Teleport(pos) and target.position=pos + RpcTeleport(destination); + } + + // client->server teleport to force position and rotation without interpolation. + // otherwise it would interpolate to a (far away) new position. + // => manually calling Teleport is the only 100% reliable solution. + [Command] + public void CmdTeleport(Vector3 destination, Quaternion rotation) + { + // client can only teleport objects that it has authority over. + if (syncDirection != SyncDirection.ClientToServer) return; + + // TODO what about host mode? + OnTeleport(destination, rotation); + + // if a client teleports, we need to broadcast to everyone else too + // TODO the teleported client should ignore the rpc though. + // otherwise if it already moved again after teleporting, + // the rpc would come a little bit later and reset it once. + // TODO or not? if client ONLY calls Teleport(pos), the position + // would only be set after the rpc. unless the client calls + // BOTH Teleport(pos) and target.position=pos + RpcTeleport(destination, rotation); + } + + [Server] + public void ServerTeleport(Vector3 destination, Quaternion rotation) + { + OnTeleport(destination, rotation); + RpcTeleport(destination, rotation); + } + + public override void ResetState() + { + base.ResetState(); // NetworkBehaviourHybrid + + // disabled objects aren't updated anymore so let's clear the buffers. + serverSnapshots.Clear(); + clientSnapshots.Clear(); + + // reset baseline + lastSerializedBaselinePosition = Vector3.zero; + lastSerializedBaselineRotation = Quaternion.identity; + lastSerializedBaselineScale = Vector3.one; + + lastDeserializedBaselinePosition = Vector3.zero; + lastDeserializedBaselineRotation = Quaternion.identity; + lastDeserializedBaselineScale = Vector3.one; + + // Prevent resistance from CharacterController + // or non-knematic Rigidbodies when teleporting. + Physics.SyncTransforms(); + + // Debug.Log($"[{name}] ResetState to baselineTick=0"); + } + + protected virtual void OnDisable() => ResetState(); + protected virtual void OnEnable() => ResetState(); + + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // OnSerialize(initial) is called every time when a player starts observing us. + // note this is _not_ called just once on spawn. + + base.OnSerialize(writer, initialState); // NetworkBehaviourHybrid + + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + // spawn message is used as first baseline. + // perf: get position/rotation directly. TransformSnapshot is too expensive. + // TransformSnapshot snapshot = ConstructSnapshot(); + target.GetLocalPositionAndRotation(out Vector3 position, out Quaternion rotation); + Vector3 scale = target.localScale; + + if (syncPosition) writer.WriteVector3(position); + if (syncRotation) writer.WriteQuaternion(rotation); + if (syncScale) writer.WriteVector3(scale); + } + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + base.OnDeserialize(reader, initialState); // NetworkBehaviourHybrid + + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + // save last deserialized baseline tick number to compare deltas against + Vector3 position = Vector3.zero; + Quaternion rotation = Quaternion.identity; + Vector3 scale = Vector3.one; + + if (syncPosition) + { + position = reader.ReadVector3(); + lastDeserializedBaselinePosition = position; + } + if (syncRotation) + { + rotation = reader.ReadQuaternion(); + lastDeserializedBaselineRotation = rotation; + } + if (syncScale) + { + scale = reader.ReadVector3(); + lastDeserializedBaselineScale = scale; + } + + // if baseline counts as delta, insert it into snapshot buffer too + if (baselineIsDelta) + OnServerToClientDeltaSync(position, rotation, scale); + } + } + // CUSTOM CHANGE /////////////////////////////////////////////////////////// + // Don't run OnGUI or draw gizmos in debug builds. + // OnGUI allocates even if it does nothing. avoid in release. + //#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if UNITY_EDITOR + // debug /////////////////////////////////////////////////////////////// + // END CUSTOM CHANGE /////////////////////////////////////////////////////// + protected virtual void OnGUI() + { + if (!showOverlay) return; + + // show data next to player for easier debugging. this is very useful! + // IMPORTANT: this is basically an ESP hack for shooter games. + // DO NOT make this available with a hotkey in release builds + if (!Debug.isDebugBuild) return; + + // project position to screen + Vector3 point = Camera.main.WorldToScreenPoint(target.position); + + // enough alpha, in front of camera and in screen? + if (point.z >= 0 && Utils.IsPointInScreen(point)) + { + GUI.color = overlayColor; + GUILayout.BeginArea(new Rect(point.x, Screen.height - point.y, 200, 100)); + + // always show both client & server buffers so it's super + // obvious if we accidentally populate both. + GUILayout.Label($"Server Buffer:{serverSnapshots.Count}"); + GUILayout.Label($"Client Buffer:{clientSnapshots.Count}"); + + GUILayout.EndArea(); + GUI.color = Color.white; + } + } + + protected virtual void DrawGizmos(SortedList buffer) + { + // only draw if we have at least two entries + if (buffer.Count < 2) return; + + // calculate threshold for 'old enough' snapshots + double threshold = NetworkTime.localTime - NetworkClient.bufferTime; + Color oldEnoughColor = new Color(0, 1, 0, 0.5f); + Color notOldEnoughColor = new Color(0.5f, 0.5f, 0.5f, 0.3f); + + // draw the whole buffer for easier debugging. + // it's worth seeing how much we have buffered ahead already + for (int i = 0; i < buffer.Count; ++i) + { + // color depends on if old enough or not + TransformSnapshot entry = buffer.Values[i]; + bool oldEnough = entry.localTime <= threshold; + Gizmos.color = oldEnough ? oldEnoughColor : notOldEnoughColor; + Gizmos.DrawCube(entry.position, Vector3.one); + } + + // extra: lines between start<->position<->goal + Gizmos.color = Color.green; + Gizmos.DrawLine(buffer.Values[0].position, target.position); + Gizmos.color = Color.white; + Gizmos.DrawLine(target.position, buffer.Values[1].position); + } + + protected virtual void OnDrawGizmos() + { + // This fires in edit mode but that spams NRE's so check isPlaying + if (!Application.isPlaying) return; + if (!showGizmos) return; + + if (isServer) DrawGizmos(serverSnapshots); + if (isClient) DrawGizmos(clientSnapshots); + } +#endif + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs.meta new file mode 100644 index 0000000..077cb28 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8f63ea2e505fd484193fb31c5c55ca73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/NetworkTransformHybrid.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs new file mode 100644 index 0000000..44a48d0 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs @@ -0,0 +1,448 @@ +// NetworkTransform V3 (reliable) by mischa (2022-10) +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Transform (Reliable)")] + public class NetworkTransformReliable : NetworkTransformBase + { + uint sendIntervalCounter = 0; + double lastSendIntervalTime = double.MinValue; + TransformSnapshot? pendingSnapshot; + + [Header("Additional Settings")] + [Tooltip("If we only sync on change, then we need to correct old snapshots if more time than sendInterval * multiplier has elapsed.\n\nOtherwise the first move will always start interpolating from the last move sequence's time, which will make it stutter when starting every time.")] + public float onlySyncOnChangeCorrectionMultiplier = 2; + public bool useFixedUpdate; + + [Header("Rotation")] + [Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] + public float rotationSensitivity = 0.01f; + + // delta compression is capable of detecting byte-level changes. + // if we scale float position to bytes, + // then small movements will only change one byte. + // this gives optimal bandwidth. + // benchmark with 0.01 precision: 130 KB/s => 60 KB/s + // benchmark with 0.1 precision: 130 KB/s => 30 KB/s + [Header("Precision")] + [Tooltip("Position is rounded in order to drastically minimize bandwidth.\n\nFor example, a precision of 0.01 rounds to a centimeter. In other words, sub-centimeter movements aren't synced until they eventually exceeded an actual centimeter.\n\nDepending on how important the object is, a precision of 0.01-0.10 (1-10 cm) is recommended.\n\nFor example, even a 1cm precision combined with delta compression cuts the Benchmark demo's bandwidth in half, compared to sending every tiny change.")] + [Range(0.00_01f, 1f)] // disallow 0 division. 1mm to 1m precision is enough range. + public float positionPrecision = 0.01f; // 1 cm + [Range(0.00_01f, 1f)] // disallow 0 division. 1mm to 1m precision is enough range. + public float scalePrecision = 0.01f; // 1 cm + + // delta compression needs to remember 'last' to compress against + protected Vector3Long lastSerializedPosition = Vector3Long.zero; + protected Vector3Long lastDeserializedPosition = Vector3Long.zero; + + protected Vector3Long lastSerializedScale = Vector3Long.zero; + protected Vector3Long lastDeserializedScale = Vector3Long.zero; + + // Used to store last sent snapshots + protected TransformSnapshot last; + + // update ////////////////////////////////////////////////////////////// + void Update() + { + // if server then always sync to others. + if (isServer) UpdateServer(); + // 'else if' because host mode shouldn't send anything to server. + // it is the server. don't overwrite anything there. + else if (isClient) UpdateClient(); + } + + void FixedUpdate() + { + if (!useFixedUpdate) return; + + if (pendingSnapshot.HasValue && !IsClientWithAuthority) + { + // Apply via base method, but in FixedUpdate + Apply(pendingSnapshot.Value, pendingSnapshot.Value); + pendingSnapshot = null; + } + } + + void LateUpdate() + { + // set dirty to trigger OnSerialize. either always, or only if changed. + // It has to be checked in LateUpdate() for onlySyncOnChange to avoid + // the possibility of Update() running first before the object's movement + // script's Update(), which then causes NT to send every alternate frame + // instead. + if (isServer || (IsClientWithAuthority && NetworkClient.ready)) + { + if (sendIntervalCounter == sendIntervalMultiplier && (!onlySyncOnChange || Changed(Construct()))) + SetDirty(); + + CheckLastSendTime(); + } + } + + protected virtual void UpdateServer() + { + // apply buffered snapshots IF client authority + // -> in server authority, server moves the object + // so no need to apply any snapshots there. + // -> don't apply for host mode player objects either, even if in + // client authority mode. if it doesn't go over the network, + // then we don't need to do anything. + // -> connectionToClient is briefly null after scene changes: + // https://github.com/MirrorNetworking/Mirror/issues/3329 + if (syncDirection == SyncDirection.ClientToServer && + connectionToClient != null && + !isOwned) + { + if (serverSnapshots.Count > 0) + { + // step the transform interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + serverSnapshots, + connectionToClient.remoteTimeline, + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + Apply(computed, to); + } + } + } + + protected virtual void UpdateClient() + { + if (useFixedUpdate) + { + if (!IsClientWithAuthority && clientSnapshots.Count > 0) + { + SnapshotInterpolation.StepInterpolation( + clientSnapshots, + NetworkTime.time, + out TransformSnapshot from, + out TransformSnapshot to, + out double t + ); + pendingSnapshot = TransformSnapshot.Interpolate(from, to, t); + } + } + else + { + // client authority, and local player (= allowed to move myself)? + if (!IsClientWithAuthority) + { + // only while we have snapshots + if (clientSnapshots.Count > 0) + { + // step the interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + clientSnapshots, + NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + Apply(computed, to); + } + } + } + } + + protected virtual void CheckLastSendTime() + { + // timeAsDouble not available in older Unity versions. + if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime)) + { + if (sendIntervalCounter == sendIntervalMultiplier) + sendIntervalCounter = 0; + sendIntervalCounter++; + } + } + + // check if position / rotation / scale changed since last sync + protected virtual bool Changed(TransformSnapshot current) => + // position is quantized and delta compressed. + // only consider it changed if the quantized representation is changed. + // careful: don't use 'serialized / deserialized last'. as it depends on sync mode etc. + QuantizedChanged(last.position, current.position, positionPrecision) || + // rotation isn't quantized / delta compressed. + // check with sensitivity. + Quaternion.Angle(last.rotation, current.rotation) > rotationSensitivity || + // scale is quantized and delta compressed. + // only consider it changed if the quantized representation is changed. + // careful: don't use 'serialized / deserialized last'. as it depends on sync mode etc. + QuantizedChanged(last.scale, current.scale, scalePrecision); + + // helper function to compare quantized representations of a Vector3 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected bool QuantizedChanged(Vector3 u, Vector3 v, float precision) + { + Compression.ScaleToLong(u, precision, out Vector3Long uQuantized); + Compression.ScaleToLong(v, precision, out Vector3Long vQuantized); + return uQuantized != vQuantized; + } + + // NT may be used on client/server/host to Owner/Observers with + // ServerToClient or ClientToServer. + // however, OnSerialize should always delta against last. + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // get current snapshot for broadcasting. + TransformSnapshot snapshot = Construct(); + + // ClientToServer optimization: + // for interpolated client owned identities, + // always broadcast the latest known snapshot so other clients can + // interpolate immediately instead of catching up too + + // TODO dirty mask? [compression is very good w/o it already] + // each vector's component is delta compressed. + // an unchanged component would still require 1 byte. + // let's use a dirty bit mask to filter those out as well. + + // initial + if (initialState) + { + // If there is a last serialized snapshot, we use it. + // This prevents the new client getting a snapshot that is different + // from what the older clients last got. If this happens, and on the next + // regular serialisation the delta compression will get wrong values. + // Notes: + // 1. Interestingly only the older clients have it wrong, because at the end + // of this function, last = snapshot which is the initial state's snapshot + // 2. Regular NTR gets by this bug because it sends every frame anyway so initialstate + // snapshot constructed would have been the same as the last anyway. + if (last.remoteTime > 0) snapshot = last; + if (syncPosition) writer.WriteVector3(snapshot.position); + if (syncRotation) + { + // (optional) smallest three compression for now. no delta. + if (compressRotation) + writer.WriteUInt(Compression.CompressQuaternion(snapshot.rotation)); + else + writer.WriteQuaternion(snapshot.rotation); + } + if (syncScale) writer.WriteVector3(snapshot.scale); + } + // delta + else + { + // int before = writer.Position; + + if (syncPosition) + { + // quantize -> delta -> varint + Compression.ScaleToLong(snapshot.position, positionPrecision, out Vector3Long quantized); + DeltaCompression.Compress(writer, lastSerializedPosition, quantized); + } + if (syncRotation) + { + // (optional) smallest three compression for now. no delta. + if (compressRotation) + writer.WriteUInt(Compression.CompressQuaternion(snapshot.rotation)); + else + writer.WriteQuaternion(snapshot.rotation); + } + if (syncScale) + { + // quantize -> delta -> varint + Compression.ScaleToLong(snapshot.scale, scalePrecision, out Vector3Long quantized); + DeltaCompression.Compress(writer, lastSerializedScale, quantized); + } + } + + // save serialized as 'last' for next delta compression + if (syncPosition) Compression.ScaleToLong(snapshot.position, positionPrecision, out lastSerializedPosition); + if (syncScale) Compression.ScaleToLong(snapshot.scale, scalePrecision, out lastSerializedScale); + + // set 'last' + last = snapshot; + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + Vector3? position = null; + Quaternion? rotation = null; + Vector3? scale = null; + + // initial + if (initialState) + { + if (syncPosition) position = reader.ReadVector3(); + if (syncRotation) + { + // (optional) smallest three compression for now. no delta. + if (compressRotation) + rotation = Compression.DecompressQuaternion(reader.ReadUInt()); + else + rotation = reader.ReadQuaternion(); + } + if (syncScale) scale = reader.ReadVector3(); + } + // delta + else + { + // varint -> delta -> quantize + if (syncPosition) + { + Vector3Long quantized = DeltaCompression.Decompress(reader, lastDeserializedPosition); + position = Compression.ScaleToFloat(quantized, positionPrecision); + } + if (syncRotation) + { + // (optional) smallest three compression for now. no delta. + if (compressRotation) + rotation = Compression.DecompressQuaternion(reader.ReadUInt()); + else + rotation = reader.ReadQuaternion(); + } + if (syncScale) + { + Vector3Long quantized = DeltaCompression.Decompress(reader, lastDeserializedScale); + scale = Compression.ScaleToFloat(quantized, scalePrecision); + } + } + + // handle depending on server / client / host. + // server has priority for host mode. + if (isServer) OnClientToServerSync(position, rotation, scale); + else if (isClient) OnServerToClientSync(position, rotation, scale); + + // save deserialized as 'last' for next delta compression + if (syncPosition) Compression.ScaleToLong(position.Value, positionPrecision, out lastDeserializedPosition); + if (syncScale) Compression.ScaleToLong(scale.Value, scalePrecision, out lastDeserializedScale); + } + + // sync //////////////////////////////////////////////////////////////// + + // local authority client sends sync message to server for broadcasting + protected virtual void OnClientToServerSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // only apply if in client authority mode + if (syncDirection != SyncDirection.ClientToServer) return; + + // protect against ever growing buffer size attacks + if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; + + // 'only sync on change' needs a correction on every new move sequence. + if (onlySyncOnChange && + NeedsCorrection(serverSnapshots, connectionToClient.remoteTimeStamp, NetworkServer.sendInterval * sendIntervalMultiplier, onlySyncOnChangeCorrectionMultiplier)) + { + RewriteHistory( + serverSnapshots, + connectionToClient.remoteTimeStamp, + NetworkTime.localTime, // arrival remote timestamp. NOT remote timeline. + NetworkServer.sendInterval * sendIntervalMultiplier, // Unity 2019 doesn't have timeAsDouble yet + GetPosition(), + GetRotation(), + GetScale()); + } + + // add a small timeline offset to account for decoupled arrival of + // NetworkTime and NetworkTransform snapshots. + // needs to be sendInterval. half sendInterval doesn't solve it. + // https://github.com/MirrorNetworking/Mirror/issues/3427 + // remove this after LocalWorldState. + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); + } + + // server broadcasts sync message to all clients + protected virtual void OnServerToClientSync(Vector3? position, Quaternion? rotation, Vector3? scale) + { + // don't apply for local player with authority + if (IsClientWithAuthority) return; + + // 'only sync on change' needs a correction on every new move sequence. + if (onlySyncOnChange && + NeedsCorrection(clientSnapshots, NetworkClient.connection.remoteTimeStamp, NetworkClient.sendInterval * sendIntervalMultiplier, onlySyncOnChangeCorrectionMultiplier)) + { + RewriteHistory( + clientSnapshots, + NetworkClient.connection.remoteTimeStamp, // arrival remote timestamp. NOT remote timeline. + NetworkTime.localTime, // Unity 2019 doesn't have timeAsDouble yet + NetworkClient.sendInterval * sendIntervalMultiplier, + GetPosition(), + GetRotation(), + GetScale()); + } + + // add a small timeline offset to account for decoupled arrival of + // NetworkTime and NetworkTransform snapshots. + // needs to be sendInterval. half sendInterval doesn't solve it. + // https://github.com/MirrorNetworking/Mirror/issues/3427 + // remove this after LocalWorldState. + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, position, rotation, scale); + } + + // only sync on change ///////////////////////////////////////////////// + // snap interp. needs a continous flow of packets. + // 'only sync on change' interrupts it while not changed. + // once it restarts, snap interp. will interp from the last old position. + // this will cause very noticeable stutter for the first move each time. + // the fix is quite simple. + + // 1. detect if the remaining snapshot is too old from a past move. + static bool NeedsCorrection( + SortedList snapshots, + double remoteTimestamp, + double bufferTime, + double toleranceMultiplier) => + snapshots.Count == 1 && + remoteTimestamp - snapshots.Keys[0] >= bufferTime * toleranceMultiplier; + + // 2. insert a fake snapshot at current position, + // exactly one 'sendInterval' behind the newly received one. + static void RewriteHistory( + SortedList snapshots, + // timestamp of packet arrival, not interpolated remote time! + double remoteTimeStamp, + double localTime, + double sendInterval, + Vector3 position, + Quaternion rotation, + Vector3 scale) + { + // clear the previous snapshot + snapshots.Clear(); + + // insert a fake one at where we used to be, + // 'sendInterval' behind the new one. + SnapshotInterpolation.InsertIfNotExists( + snapshots, + NetworkClient.snapshotSettings.bufferLimit, + new TransformSnapshot( + remoteTimeStamp - sendInterval, // arrival remote timestamp. NOT remote time. + localTime - sendInterval, // Unity 2019 doesn't have timeAsDouble yet + position, + rotation, + scale + ) + ); + } + + // reset state for next session. + // do not ever call this during a session (i.e. after teleport). + // calling this will break delta compression. + public override void ResetState() + { + base.ResetState(); + + // reset delta + lastSerializedPosition = Vector3Long.zero; + lastDeserializedPosition = Vector3Long.zero; + + lastSerializedScale = Vector3Long.zero; + lastDeserializedScale = Vector3Long.zero; + + // reset 'last' for delta too + last = new TransformSnapshot(0, 0, Vector3.zero, Quaternion.identity, Vector3.zero); + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta new file mode 100644 index 0000000..c8be862 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8ff3ba0becae47b8b9381191598957c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/NetworkTransformReliable.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs new file mode 100644 index 0000000..adac721 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs @@ -0,0 +1,462 @@ +// NetworkTransform V2 by mischa (2021-07) +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [AddComponentMenu("Network/Network Transform (Unreliable)")] + public class NetworkTransformUnreliable : NetworkTransformBase + { + uint sendIntervalCounter = 0; + double lastSendIntervalTime = double.MinValue; + TransformSnapshot? pendingSnapshot; + + [Header("Additional Settings")] + // Testing under really bad network conditions, 2%-5% packet loss and 250-1200ms ping, 5 proved to eliminate any twitching, however this should not be the default as it is a rare case Developers may want to cover. + [Tooltip("How much time, as a multiple of send interval, has passed before clearing buffers.\nA larger buffer means more delay, but results in smoother movement.\nExample: 1 for faster responses minimal smoothing, 5 covers bad pings but has noticable delay, 3 is recommended for balanced results.")] + public float bufferResetMultiplier = 3; + public bool useFixedUpdate; + + [Header("Sensitivity"), Tooltip("Sensitivity of changes needed before an updated state is sent over the network")] + public float positionSensitivity = 0.01f; + public float rotationSensitivity = 0.01f; + public float scaleSensitivity = 0.01f; + + // Used to store last sent snapshots + protected TransformSnapshot lastSnapshot; + protected Changed cachedChangedComparison; + protected bool hasSentUnchangedPosition; + + // update ////////////////////////////////////////////////////////////// + // Update applies interpolation + void Update() + { + if (isServer) UpdateServerInterpolation(); + // for all other clients (and for local player if !authority), + // we need to apply snapshots from the buffer. + // 'else if' because host mode shouldn't interpolate client + else if (isClient && !IsClientWithAuthority) UpdateClientInterpolation(); + } + + void FixedUpdate() + { + if (!useFixedUpdate) return; + + if (pendingSnapshot.HasValue) + { + Apply(pendingSnapshot.Value, pendingSnapshot.Value); + pendingSnapshot = null; + } + } + + // LateUpdate broadcasts. + // movement scripts may change positions in Update. + // use LateUpdate to ensure changes are detected in the same frame. + // otherwise this may run before user update, delaying detection until next frame. + // this could cause visible jitter. + void LateUpdate() + { + // if server then always sync to others. + if (isServer) UpdateServerBroadcast(); + // client authority, and local player (= allowed to move myself)? + // 'else if' because host mode shouldn't send anything to server. + // it is the server. don't overwrite anything there. + else if (isClient && IsClientWithAuthority) UpdateClientBroadcast(); + } + + protected virtual void CheckLastSendTime() + { + // We check interval every frame, and then send if interval is reached. + // So by the time sendIntervalCounter == sendIntervalMultiplier, data is sent, + // thus we reset the counter here. + // This fixes previous issue of, if sendIntervalMultiplier = 1, we send every frame, + // because intervalCounter is always = 1 in the previous version. + + // Changing == to >= https://github.com/MirrorNetworking/Mirror/issues/3571 + + if (sendIntervalCounter >= sendIntervalMultiplier) + sendIntervalCounter = 0; + + // timeAsDouble not available in older Unity versions. + if (AccurateInterval.Elapsed(NetworkTime.localTime, NetworkServer.sendInterval, ref lastSendIntervalTime)) + sendIntervalCounter++; + } + + void UpdateServerBroadcast() + { + // broadcast to all clients each 'sendInterval' + // (client with authority will drop the rpc) + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + // + // Checks to ensure server only sends snapshots if object is + // on server authority(!clientAuthority) mode because on client + // authority mode snapshots are broadcasted right after the authoritative + // client updates server in the command function(see above), OR, + // since host does not send anything to update the server, any client + // authoritative movement done by the host will have to be broadcasted + // here by checking IsClientWithAuthority. + // TODO send same time that NetworkServer sends time snapshot? + CheckLastSendTime(); + + if (sendIntervalCounter == sendIntervalMultiplier && // same interval as time interpolation! + (syncDirection == SyncDirection.ServerToClient || IsClientWithAuthority)) + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + TransformSnapshot snapshot = Construct(); + + cachedChangedComparison = CompareChangedSnapshots(snapshot); + + if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + SyncData syncData = new SyncData(cachedChangedComparison, snapshot); + + RpcServerToClientSync(syncData); + + if (cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + UpdateLastSentSnapshot(cachedChangedComparison, snapshot); + } + } + } + + void UpdateServerInterpolation() + { + // apply buffered snapshots IF client authority + // -> in server authority, server moves the object + // so no need to apply any snapshots there. + // -> don't apply for host mode player objects either, even if in + // client authority mode. if it doesn't go over the network, + // then we don't need to do anything. + // -> connectionToClient is briefly null after scene changes: + // https://github.com/MirrorNetworking/Mirror/issues/3329 + if (syncDirection == SyncDirection.ClientToServer && + connectionToClient != null && + !isOwned) + { + if (serverSnapshots.Count == 0) return; + + // step the transform interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + serverSnapshots, + connectionToClient.remoteTimeline, + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + if (useFixedUpdate) + pendingSnapshot = computed; + else + Apply(computed, to); + } + } + + void UpdateClientBroadcast() + { + // https://github.com/vis2k/Mirror/pull/2992/ + if (!NetworkClient.ready) return; + + // send to server each 'sendInterval' + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + CheckLastSendTime(); + if (sendIntervalCounter == sendIntervalMultiplier) // same interval as time interpolation! + { + // send snapshot without timestamp. + // receiver gets it from batch timestamp to save bandwidth. + TransformSnapshot snapshot = Construct(); + + cachedChangedComparison = CompareChangedSnapshots(snapshot); + + if ((cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) && hasSentUnchangedPosition && onlySyncOnChange) { return; } + + SyncData syncData = new SyncData(cachedChangedComparison, snapshot); + + CmdClientToServerSync(syncData); + + if (cachedChangedComparison == Changed.None || cachedChangedComparison == Changed.CompressRot) + { + hasSentUnchangedPosition = true; + } + else + { + hasSentUnchangedPosition = false; + UpdateLastSentSnapshot(cachedChangedComparison, snapshot); + } + } + } + + void UpdateClientInterpolation() + { + // only while we have snapshots + if (clientSnapshots.Count == 0) return; + + // step the interpolation without touching time. + // NetworkClient is responsible for time globally. + SnapshotInterpolation.StepInterpolation( + clientSnapshots, + NetworkTime.time, // == NetworkClient.localTimeline from snapshot interpolation + out TransformSnapshot from, + out TransformSnapshot to, + out double t); + + // interpolate & apply + TransformSnapshot computed = TransformSnapshot.Interpolate(from, to, t); + if (useFixedUpdate) + pendingSnapshot = computed; + else + Apply(computed, to); + } + + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + if (syncPosition) writer.WriteVector3(GetPosition()); + if (syncRotation) writer.WriteQuaternion(GetRotation()); + if (syncScale) writer.WriteVector3(GetScale()); + } + } + + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + // sync target component's position on spawn. + // fixes https://github.com/vis2k/Mirror/pull/3051/ + // (Spawn message wouldn't sync NTChild positions either) + if (initialState) + { + if (syncPosition) SetPosition(reader.ReadVector3()); + if (syncRotation) SetRotation(reader.ReadQuaternion()); + if (syncScale) SetScale(reader.ReadVector3()); + } + } + + protected virtual void UpdateLastSentSnapshot(Changed change, TransformSnapshot currentSnapshot) + { + if (change == Changed.None || change == Changed.CompressRot) return; + + if ((change & Changed.PosX) > 0) lastSnapshot.position.x = currentSnapshot.position.x; + if ((change & Changed.PosY) > 0) lastSnapshot.position.y = currentSnapshot.position.y; + if ((change & Changed.PosZ) > 0) lastSnapshot.position.z = currentSnapshot.position.z; + + if (compressRotation) + { + if ((change & Changed.Rot) > 0) lastSnapshot.rotation = currentSnapshot.rotation; + } + else + { + Vector3 newRotation; + newRotation.x = (change & Changed.RotX) > 0 ? currentSnapshot.rotation.eulerAngles.x : lastSnapshot.rotation.eulerAngles.x; + newRotation.y = (change & Changed.RotY) > 0 ? currentSnapshot.rotation.eulerAngles.y : lastSnapshot.rotation.eulerAngles.y; + newRotation.z = (change & Changed.RotZ) > 0 ? currentSnapshot.rotation.eulerAngles.z : lastSnapshot.rotation.eulerAngles.z; + + lastSnapshot.rotation = Quaternion.Euler(newRotation); + } + + if ((change & Changed.Scale) > 0) lastSnapshot.scale = currentSnapshot.scale; + } + + // Returns true if position, rotation AND scale are unchanged, within given sensitivity range. + // Note the sensitivity comparison are different for pos, rot and scale. + protected virtual Changed CompareChangedSnapshots(TransformSnapshot currentSnapshot) + { + Changed change = Changed.None; + + if (syncPosition) + { + bool positionChanged = Vector3.SqrMagnitude(lastSnapshot.position - currentSnapshot.position) > positionSensitivity * positionSensitivity; + if (positionChanged) + { + if (Mathf.Abs(lastSnapshot.position.x - currentSnapshot.position.x) > positionSensitivity) change |= Changed.PosX; + if (Mathf.Abs(lastSnapshot.position.y - currentSnapshot.position.y) > positionSensitivity) change |= Changed.PosY; + if (Mathf.Abs(lastSnapshot.position.z - currentSnapshot.position.z) > positionSensitivity) change |= Changed.PosZ; + } + } + + if (syncRotation) + { + if (compressRotation) + { + bool rotationChanged = Quaternion.Angle(lastSnapshot.rotation, currentSnapshot.rotation) > rotationSensitivity; + if (rotationChanged) + { + // Here we set all Rot enum flags, to tell us if there was a change in rotation + // when using compression. If no change, we don't write the compressed Quat. + change |= Changed.CompressRot; + change |= Changed.Rot; + } + else + { + change |= Changed.CompressRot; + } + } + else + { + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.x - currentSnapshot.rotation.eulerAngles.x) > rotationSensitivity) change |= Changed.RotX; + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.y - currentSnapshot.rotation.eulerAngles.y) > rotationSensitivity) change |= Changed.RotY; + if (Mathf.Abs(lastSnapshot.rotation.eulerAngles.z - currentSnapshot.rotation.eulerAngles.z) > rotationSensitivity) change |= Changed.RotZ; + } + } + + if (syncScale) + { + if (Vector3.SqrMagnitude(lastSnapshot.scale - currentSnapshot.scale) > scaleSensitivity * scaleSensitivity) change |= Changed.Scale; + } + + return change; + } + + [Command(channel = Channels.Unreliable)] + void CmdClientToServerSync(SyncData syncData) + { + OnClientToServerSync(syncData); + //For client authority, immediately pass on the client snapshot to all other + //clients instead of waiting for server to send its snapshots. + if (syncDirection == SyncDirection.ClientToServer) + RpcServerToClientSync(syncData); + } + + protected virtual void OnClientToServerSync(SyncData syncData) + { + // only apply if in client authority mode + if (syncDirection != SyncDirection.ClientToServer) return; + + // protect against ever growing buffer size attacks + if (serverSnapshots.Count >= connectionToClient.snapshotBufferSizeLimit) return; + + // only player owned objects (with a connection) can send to + // server. we can get the timestamp from the connection. + double timestamp = connectionToClient.remoteTimeStamp; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkClient.sendInterval; + + if (serverSnapshots.Count > 0 && serverSnapshots.Values[serverSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + UpdateSyncData(ref syncData, serverSnapshots); + + AddSnapshot(serverSnapshots, connectionToClient.remoteTimeStamp + timeStampAdjustment + offset, syncData.position, syncData.quatRotation, syncData.scale); + } + + [ClientRpc(channel = Channels.Unreliable)] + void RpcServerToClientSync(SyncData syncData) => + OnServerToClientSync(syncData); + + protected virtual void OnServerToClientSync(SyncData syncData) + { + // in host mode, the server sends rpcs to all clients. + // the host client itself will receive them too. + // -> host server is always the source of truth + // -> we can ignore any rpc on the host client + // => otherwise host objects would have ever growing clientBuffers + // (rpc goes to clients. if isServer is true too then we are host) + if (isServer) return; + + // don't apply for local player with authority + if (IsClientWithAuthority) return; + + // on the client, we receive rpcs for all entities. + // not all of them have a connectionToServer. + // but all of them go through NetworkClient.connection. + // we can get the timestamp from there. + double timestamp = NetworkClient.connection.remoteTimeStamp; + + if (onlySyncOnChange) + { + double timeIntervalCheck = bufferResetMultiplier * sendIntervalMultiplier * NetworkServer.sendInterval; + + if (clientSnapshots.Count > 0 && clientSnapshots.Values[clientSnapshots.Count - 1].remoteTime + timeIntervalCheck < timestamp) + ResetState(); + } + + UpdateSyncData(ref syncData, clientSnapshots); + + AddSnapshot(clientSnapshots, NetworkClient.connection.remoteTimeStamp + timeStampAdjustment + offset, syncData.position, syncData.quatRotation, syncData.scale); + } + + protected virtual void UpdateSyncData(ref SyncData syncData, SortedList snapshots) + { + if (syncData.changedDataByte == Changed.None || syncData.changedDataByte == Changed.CompressRot) + { + syncData.position = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position : GetPosition(); + syncData.quatRotation = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation(); + syncData.scale = snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale(); + } + else + { + // Just going to update these without checking if syncposition or not, + // because if not syncing position, NT will not apply any position data + // to the target during Apply(). + + syncData.position.x = (syncData.changedDataByte & Changed.PosX) > 0 ? syncData.position.x : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.x : GetPosition().x); + syncData.position.y = (syncData.changedDataByte & Changed.PosY) > 0 ? syncData.position.y : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.y : GetPosition().y); + syncData.position.z = (syncData.changedDataByte & Changed.PosZ) > 0 ? syncData.position.z : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].position.z : GetPosition().z); + + // If compressRot is true, we already have the Quat in syncdata. + if ((syncData.changedDataByte & Changed.CompressRot) == 0) + { + syncData.vecRotation.x = (syncData.changedDataByte & Changed.RotX) > 0 ? syncData.vecRotation.x : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.x : GetRotation().eulerAngles.x); + syncData.vecRotation.y = (syncData.changedDataByte & Changed.RotY) > 0 ? syncData.vecRotation.y : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.y : GetRotation().eulerAngles.y); ; + syncData.vecRotation.z = (syncData.changedDataByte & Changed.RotZ) > 0 ? syncData.vecRotation.z : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation.eulerAngles.z : GetRotation().eulerAngles.z); + + syncData.quatRotation = Quaternion.Euler(syncData.vecRotation); + } + else + { + syncData.quatRotation = (syncData.changedDataByte & Changed.Rot) > 0 ? syncData.quatRotation : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].rotation : GetRotation()); + } + + syncData.scale = (syncData.changedDataByte & Changed.Scale) > 0 ? syncData.scale : (snapshots.Count > 0 ? snapshots.Values[snapshots.Count - 1].scale : GetScale()); + } + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta new file mode 100644 index 0000000..e5e968f --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a553cb17010b2403e8523b558bffbc14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/NetworkTransformUnreliable.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs new file mode 100644 index 0000000..01b863c --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs @@ -0,0 +1,68 @@ +// snapshot for snapshot interpolation +// https://gafferongames.com/post/snapshot_interpolation/ +// position, rotation, scale for compatibility for now. +using UnityEngine; + +namespace Mirror +{ + // NetworkTransform Snapshot + public struct TransformSnapshot : Snapshot + { + // time or sequence are needed to throw away older snapshots. + // + // glenn fiedler starts with a 16 bit sequence number. + // supposedly this is meant as a simplified example. + // in the end we need the remote timestamp for accurate interpolation + // and buffering over time. + // + // note: in theory, IF server sends exactly(!) at the same interval then + // the 16 bit ushort timestamp would be enough to calculate the + // remote time (sequence * sendInterval). but Unity's update is + // not guaranteed to run on the exact intervals / do catchup. + // => remote timestamp is better for now + // + // [REMOTE TIME, NOT LOCAL TIME] + // => DOUBLE for long term accuracy & batching gives us double anyway + public double remoteTime { get; set; } + + // the local timestamp (when we received it) + // used to know if the first two snapshots are old enough to start. + public double localTime { get; set; } + + public Vector3 position; + public Quaternion rotation; + public Vector3 scale; + + public TransformSnapshot(double remoteTime, double localTime, Vector3 position, Quaternion rotation, Vector3 scale) + { + this.remoteTime = remoteTime; + this.localTime = localTime; + this.position = position; + this.rotation = rotation; + this.scale = scale; + } + + public static TransformSnapshot Interpolate(TransformSnapshot from, TransformSnapshot to, double t) + { + // NOTE: + // Vector3 & Quaternion components are float anyway, so we can + // keep using the functions with 't' as float instead of double. + return new TransformSnapshot( + // interpolated snapshot is applied directly. don't need timestamps. + 0, 0, + // lerp position/rotation/scale unclamped in case we ever need + // to extrapolate. atm SnapshotInterpolation never does. + Vector3.LerpUnclamped(from.position, to.position, (float)t), + // IMPORTANT: LerpUnclamped(0, 60, 1.5) extrapolates to ~86. + // SlerpUnclamped(0, 60, 1.5) extrapolates to 90! + // (0, 90, 1.5) is even worse. for Lerp. + // => Slerp works way better for our euler angles. + Quaternion.SlerpUnclamped(from.rotation, to.rotation, (float)t), + Vector3.LerpUnclamped(from.scale, to.scale, (float)t) + ); + } + + public override string ToString() => + $"TransformSnapshot(remoteTime={remoteTime:F2}, localTime={localTime:F2}, pos={position}, rot={rotation}, scale={scale})"; + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta new file mode 100644 index 0000000..b8e9173 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d3dae77b43dc4e1dbb2012924b2da79c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/TransformSnapshot.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs new file mode 100644 index 0000000..9b6d51c --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs @@ -0,0 +1,156 @@ +using UnityEngine; +using System; +using Mirror; + +namespace Mirror +{ + [Serializable] + public struct SyncData + { + public Changed changedDataByte; + public Vector3 position; + public Quaternion quatRotation; + public Vector3 vecRotation; + public Vector3 scale; + + public SyncData(Changed _dataChangedByte, Vector3 _position, Quaternion _rotation, Vector3 _scale) + { + this.changedDataByte = _dataChangedByte; + this.position = _position; + this.quatRotation = _rotation; + this.vecRotation = quatRotation.eulerAngles; + this.scale = _scale; + } + + public SyncData(Changed _dataChangedByte, TransformSnapshot _snapshot) + { + this.changedDataByte = _dataChangedByte; + this.position = _snapshot.position; + this.quatRotation = _snapshot.rotation; + this.vecRotation = quatRotation.eulerAngles; + this.scale = _snapshot.scale; + } + + public SyncData(Changed _dataChangedByte, Vector3 _position, Vector3 _vecRotation, Vector3 _scale) + { + this.changedDataByte = _dataChangedByte; + this.position = _position; + this.vecRotation = _vecRotation; + this.quatRotation = Quaternion.Euler(vecRotation); + this.scale = _scale; + } + } + + [Flags] + public enum Changed : byte + { + None = 0, + PosX = 1 << 0, + PosY = 1 << 1, + PosZ = 1 << 2, + CompressRot = 1 << 3, + RotX = 1 << 4, + RotY = 1 << 5, + RotZ = 1 << 6, + Scale = 1 << 7, + + Pos = PosX | PosY | PosZ, + Rot = RotX | RotY | RotZ + } + + + public static class SyncDataReaderWriter + { + public static void WriteSyncData(this NetworkWriter writer, SyncData syncData) + { + writer.WriteByte((byte)syncData.changedDataByte); + + // Write position + if ((syncData.changedDataByte & Changed.PosX) > 0) + { + writer.WriteFloat(syncData.position.x); + } + + if ((syncData.changedDataByte & Changed.PosY) > 0) + { + writer.WriteFloat(syncData.position.y); + } + + if ((syncData.changedDataByte & Changed.PosZ) > 0) + { + writer.WriteFloat(syncData.position.z); + } + + // Write rotation + if ((syncData.changedDataByte & Changed.CompressRot) > 0) + { + if((syncData.changedDataByte & Changed.Rot) > 0) + { + writer.WriteUInt(Compression.CompressQuaternion(syncData.quatRotation)); + } + } + else + { + if ((syncData.changedDataByte & Changed.RotX) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.x); + } + + if ((syncData.changedDataByte & Changed.RotY) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.y); + } + + if ((syncData.changedDataByte & Changed.RotZ) > 0) + { + writer.WriteFloat(syncData.quatRotation.eulerAngles.z); + } + } + + // Write scale + if ((syncData.changedDataByte & Changed.Scale) > 0) + { + writer.WriteVector3(syncData.scale); + } + } + + public static SyncData ReadSyncData(this NetworkReader reader) + { + Changed changedData = (Changed)reader.ReadByte(); + + // If we have nothing to read here, let's say because posX is unchanged, then we can write anything + // for now, but in the NT, we will need to check changedData again, to put the right values of the axis + // back. We don't have it here. + + Vector3 position = + new Vector3( + (changedData & Changed.PosX) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.PosY) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.PosZ) > 0 ? reader.ReadFloat() : 0 + ); + + Vector3 vecRotation = new Vector3(); + Quaternion quatRotation = new Quaternion(); + + if ((changedData & Changed.CompressRot) > 0) + { + quatRotation = (changedData & Changed.RotX) > 0 ? Compression.DecompressQuaternion(reader.ReadUInt()) : new Quaternion(); + } + else + { + vecRotation = + new Vector3( + (changedData & Changed.RotX) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.RotY) > 0 ? reader.ReadFloat() : 0, + (changedData & Changed.RotZ) > 0 ? reader.ReadFloat() : 0 + ); + } + + Vector3 scale = (changedData & Changed.Scale) == Changed.Scale ? reader.ReadVector3() : new Vector3(); + + SyncData _syncData = (changedData & Changed.CompressRot) > 0 ? new SyncData(changedData, position, quatRotation, scale) : new SyncData(changedData, position, vecRotation, scale); + + return _syncData; + } + } +} diff --git a/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta new file mode 100644 index 0000000..2f2d647 --- /dev/null +++ b/Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a1c0832ca88e749ff96fe04cebb617ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/NetworkTransform/TransformSyncData.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody.meta b/Assets/Mirror/Components/PredictedRigidbody.meta new file mode 100644 index 0000000..a513fe0 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09cc6745984c453a8cfb4cf4244d2570 +timeCreated: 1693576410 diff --git a/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat new file mode 100644 index 0000000..ff29a73 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat @@ -0,0 +1,85 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: LocalGhostMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.92 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 0, b: 0.067070484, a: 0.15686275} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta new file mode 100644 index 0000000..4a9b6eb --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 411a48b4a197d4924bec3e3809bc9320 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/LocalGhostMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs new file mode 100644 index 0000000..02abda3 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs @@ -0,0 +1,1021 @@ +// PredictedRigidbody which stores & indidvidually rewinds history per Rigidbody. +// +// This brings significant performance savings because: +// - if a scene has 1000 objects +// - and a player interacts with say 3 objects at a time +// - Physics.Simulate() would resimulate 1000 objects +// - where as this component only resimulates the 3 changed objects +// +// The downside is that history rewinding is done manually via Vector math, +// instead of real physics. It's not 100% correct - but it sure is fast! +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public enum PredictionMode { Smooth, Fast } + + // [RequireComponent(typeof(Rigidbody))] <- RB is moved out at runtime, can't require it. + public class PredictedRigidbody : NetworkBehaviour + { + Transform tf; // this component is performance critical. cache .transform getter! + + // Prediction sometimes moves the Rigidbody to a ghost object. + // .predictedRigidbody is always kept up to date to wherever the RB is. + // other components should use this when accessing Rigidbody. + public Rigidbody predictedRigidbody; + Transform predictedRigidbodyTransform; // predictedRigidbody.transform for performance (Get/SetPositionAndRotation) + + Vector3 lastPosition; + + // motion smoothing happen on-demand, because it requires moving physics components to another GameObject. + // this only starts at a given velocity and ends when stopped moving. + // to avoid constant on/off/on effects, it also stays on for a minimum time. + [Header("Motion Smoothing")] + [Tooltip("Prediction supports two different modes: Smooth and Fast:\n\nSmooth: Physics are separated from the GameObject & applied in the background. Rendering smoothly follows the physics for perfectly smooth interpolation results. Much softer, can be even too soft where sharp collisions won't look as sharp (i.e. Billiard balls avoid the wall before even hitting it).\n\nFast: Physics remain on the GameObject and corrections are applied hard. Much faster since we don't need to update a separate GameObject, a bit harsher, more precise.")] + public PredictionMode mode = PredictionMode.Smooth; + [Tooltip("Smoothing via Ghost-following only happens on demand, while moving with a minimum velocity.")] + public float motionSmoothingVelocityThreshold = 0.1f; + float motionSmoothingVelocityThresholdSqr; // ² cached in Awake + public float motionSmoothingAngularVelocityThreshold = 5.0f; // Billiards demo: 0.1 is way too small, takes forever for IsMoving()==false + float motionSmoothingAngularVelocityThresholdSqr; // ² cached in Awake + public float motionSmoothingTimeTolerance = 0.5f; + double motionSmoothingLastMovedTime; + + // client keeps state history for correction & reconciliation. + // this needs to be a SortedList because we need to be able to insert inbetween. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + [Header("State History")] + public int stateHistoryLimit = 32; // 32 x 50 ms = 1.6 seconds is definitely enough + readonly SortedList stateHistory = new SortedList(); + public float recordInterval = 0.050f; + + [Tooltip("(Optional) performance optimization where FixedUpdate.RecordState() only inserts state into history if the state actually changed.\nThis is generally a good idea.")] + public bool onlyRecordChanges = true; + + [Tooltip("(Optional) performance optimization where received state is compared to the LAST recorded state first, before sampling the whole history.\n\nThis can save significant traversal overhead for idle objects with a tiny chance of missing corrections for objects which revisisted the same position in the recent history twice.")] + public bool compareLastFirst = true; + + [Header("Reconciliation")] + [Tooltip("Correction threshold in meters. For example, 0.1 means that if the client is off by more than 10cm, it gets corrected.")] + public double positionCorrectionThreshold = 0.10; + double positionCorrectionThresholdSqr; // ² cached in Awake + [Tooltip("Correction threshold in degrees. For example, 5 means that if the client is off by more than 5 degrees, it gets corrected.")] + public double rotationCorrectionThreshold = 5; + + [Tooltip("Applying server corrections one frame ahead gives much better results. We don't know why yet, so this is an option for now.")] + public bool oneFrameAhead = true; + + [Header("Smoothing")] + [Tooltip("Snap to the server state directly when velocity is < threshold. This is useful to reduce jitter/fighting effects before coming to rest.\nNote this applies position, rotation and velocity(!) so it's still smooth.")] + public float snapThreshold = 2; // 0.5 has too much fighting-at-rest, 2 seems ideal. + + [Header("Visual Interpolation")] + [Tooltip("After creating the visual interpolation object, keep showing the original Rigidbody with a ghost (transparent) material for debugging.")] + public bool showGhost = true; + [Tooltip("Physics components are moved onto a ghost object beyond this threshold. Main object visually interpolates to it.")] + public float ghostVelocityThreshold = 0.1f; + + [Tooltip("After creating the visual interpolation object, replace this object's renderer materials with the ghost (ideally transparent) material.")] + public Material localGhostMaterial; + public Material remoteGhostMaterial; + + [Tooltip("Performance optimization: only create/destroy ghosts every n-th frame is enough.")] + public int checkGhostsEveryNthFrame = 4; + + [Tooltip("How fast to interpolate to the target position, relative to how far we are away from it.\nHigher value will be more jitter but sharper moves, lower value will be less jitter but a little too smooth / rounded moves.")] + public float positionInterpolationSpeed = 15; // 10 is a little too low for billiards at least + public float rotationInterpolationSpeed = 10; + + [Tooltip("Teleport if we are further than 'multiplier x collider size' behind.")] + public float teleportDistanceMultiplier = 10; + + [Header("Bandwidth")] + [Tooltip("Reduce sends while velocity==0. Client's objects may slightly move due to gravity/physics, so we still want to send corrections occasionally even if an object is idle on the server the whole time.")] + public bool reduceSendsWhileIdle = true; + + // Rigidbody & Collider are moved out into a separate object. + // this way the visual object can smoothly follow. + protected GameObject physicsCopy; + // protected Transform physicsCopyTransform; // caching to avoid GetComponent + // protected Rigidbody physicsCopyRigidbody => rb; // caching to avoid GetComponent + // protected Collider physicsCopyCollider; // caching to avoid GetComponent + float smoothFollowThreshold; // caching to avoid calculation in LateUpdate + float smoothFollowThresholdSqr; // caching to avoid calculation in LateUpdate + + // we also create one extra ghost for the exact known server state. + protected GameObject remoteCopy; + + // joints + Vector3 initialPosition; + Quaternion initialRotation; + // Vector3 initialScale; // don't change scale for now. causes issues with parenting. + + Color originalColor; + + protected virtual void Awake() + { + tf = transform; + predictedRigidbody = GetComponent(); + if (predictedRigidbody == null) throw new InvalidOperationException($"Prediction: {name} is missing a Rigidbody component."); + predictedRigidbodyTransform = predictedRigidbody.transform; + + // in fast mode, we need to force enable Rigidbody.interpolation. + // otherwise there's not going to be any smoothing whatsoever. + if (mode == PredictionMode.Fast) + { + predictedRigidbody.interpolation = RigidbodyInterpolation.Interpolate; + } + + // cache some threshold to avoid calculating them in LateUpdate + float colliderSize = GetComponentInChildren().bounds.size.magnitude; + smoothFollowThreshold = colliderSize * teleportDistanceMultiplier; + smoothFollowThresholdSqr = smoothFollowThreshold * smoothFollowThreshold; + + // cache initial position/rotation/scale to be used when moving physics components (configurable joints' range of motion) + initialPosition = tf.position; + initialRotation = tf.rotation; + // initialScale = tf.localScale; + + // cache ² computations + motionSmoothingVelocityThresholdSqr = motionSmoothingVelocityThreshold * motionSmoothingVelocityThreshold; + motionSmoothingAngularVelocityThresholdSqr = motionSmoothingAngularVelocityThreshold * motionSmoothingAngularVelocityThreshold; + positionCorrectionThresholdSqr = positionCorrectionThreshold * positionCorrectionThreshold; + } + + protected virtual void CopyRenderersAsGhost(GameObject destination, Material material) + { + // find the MeshRenderer component, which sometimes is on a child. + MeshRenderer originalMeshRenderer = GetComponentInChildren(true); + MeshFilter originalMeshFilter = GetComponentInChildren(true); + if (originalMeshRenderer != null && originalMeshFilter != null) + { + MeshFilter meshFilter = destination.AddComponent(); + meshFilter.mesh = originalMeshFilter.mesh; + + MeshRenderer meshRenderer = destination.AddComponent(); + meshRenderer.material = originalMeshRenderer.material; + + // renderers often have multiple materials. copy all. + if (originalMeshRenderer.materials != null) + { + Material[] materials = new Material[originalMeshRenderer.materials.Length]; + for (int i = 0; i < materials.Length; ++i) + { + materials[i] = material; + } + meshRenderer.materials = materials; // need to reassign to see it in effect + } + } + // if we didn't find a renderer, show a warning + else Debug.LogWarning($"PredictedRigidbody: {name} found no renderer to copy onto the visual object. If you are using a custom setup, please overwrite PredictedRigidbody.CreateVisualCopy()."); + } + + // instantiate a physics-only copy of the gameobject to apply corrections. + // this way the main visual object can smoothly follow. + // it's best to separate the physics instead of separating the renderers. + // some projects have complex rendering / animation setups which we can't touch. + // besides, Rigidbody+Collider are two components, where as renders may be many. + protected virtual void CreateGhosts() + { + // skip if host mode or already separated + if (isServer || physicsCopy != null) return; + + // Debug.Log($"Separating Physics for {name}"); // logging this allocates too much + + // create an empty GameObject with the same name + _Physical + // it's important to copy world position/rotation/scale, not local! + // because the original object may be a child of another. + // + // for example: + // parent (scale=1.5) + // child (scale=0.5) + // + // if we copy localScale then the copy has scale=0.5, where as the + // original would have a global scale of ~1.0. + physicsCopy = new GameObject($"{name}_Physical"); + + // assign the same Layer for the physics copy. + // games may use a custom physics collision matrix, layer matters. + physicsCopy.layer = gameObject.layer; + + // add the PredictedRigidbodyPhysical component + PredictedRigidbodyPhysicsGhost physicsGhostRigidbody = physicsCopy.AddComponent(); + physicsGhostRigidbody.target = tf; + + // when moving (Configurable)Joints, their range of motion is + // relative to the initial position. if we move them after the + // GameObject rotated, the range of motion is wrong. + // the easiest solution is to move to initial position, + // then move physics components, then move back. + // => remember previous + Vector3 position = tf.position; + Quaternion rotation = tf.rotation; + // Vector3 scale = tf.localScale; // don't change scale for now. causes issues with parenting. + // => reset to initial + physicsGhostRigidbody.transform.position = tf.position = initialPosition; + physicsGhostRigidbody.transform.rotation = tf.rotation = initialRotation; + physicsGhostRigidbody.transform.localScale = tf.lossyScale;// world scale! // = initialScale; // don't change scale for now. causes issues with parenting. + // => move physics components + PredictionUtils.MovePhysicsComponents(gameObject, physicsCopy); + // => reset previous + physicsGhostRigidbody.transform.position = tf.position = position; + physicsGhostRigidbody.transform.rotation = tf.rotation = rotation; + //physicsGhostRigidbody.transform.localScale = tf.lossyScale; // world scale! //= scale; // don't change scale for now. causes issues with parenting. + + // show ghost by copying all renderers / materials with ghost material applied + if (showGhost) + { + // one for the locally predicted rigidbody + CopyRenderersAsGhost(physicsCopy, localGhostMaterial); + + // one for the latest remote state for comparison + // it's important to copy world position/rotation/scale, not local! + // because the original object may be a child of another. + // + // for example: + // parent (scale=1.5) + // child (scale=0.5) + // + // if we copy localScale then the copy has scale=0.5, where as the + // original would have a global scale of ~1.0. + remoteCopy = new GameObject($"{name}_Remote"); + remoteCopy.transform.position = tf.position; // world position! + remoteCopy.transform.rotation = tf.rotation; // world rotation! + remoteCopy.transform.localScale = tf.lossyScale; // world scale! + CopyRenderersAsGhost(remoteCopy, remoteGhostMaterial); + } + + // assign our Rigidbody reference to the ghost + predictedRigidbody = physicsCopy.GetComponent(); + predictedRigidbodyTransform = predictedRigidbody.transform; + } + + protected virtual void DestroyGhosts() + { + // move the copy's Rigidbody back onto self. + // important for scene objects which may be reused for AOI spawn/despawn. + // otherwise next time they wouldn't have a collider anymore. + if (physicsCopy != null) + { + // when moving (Configurable)Joints, their range of motion is + // relative to the initial position. if we move them after the + // GameObject rotated, the range of motion is wrong. + // the easiest solution is to move to initial position, + // then move physics components, then move back. + // => remember previous + Vector3 position = tf.position; + Quaternion rotation = tf.rotation; + Vector3 scale = tf.localScale; + // => reset to initial + physicsCopy.transform.position = tf.position = initialPosition; + physicsCopy.transform.rotation = tf.rotation = initialRotation; + physicsCopy.transform.localScale = tf.lossyScale;// = initialScale; + // => move physics components + PredictionUtils.MovePhysicsComponents(physicsCopy, gameObject); + // => reset previous + tf.position = position; + tf.rotation = rotation; + tf.localScale = scale; + + // when moving components back, we need to undo the joints initial-delta rotation that we added. + Destroy(physicsCopy); + + // reassign our Rigidbody reference + predictedRigidbody = GetComponent(); + predictedRigidbodyTransform = predictedRigidbody.transform; + } + + // simply destroy the remote copy + if (remoteCopy != null) Destroy(remoteCopy); + } + + // this shows in profiler LateUpdates! need to make this as fast as possible! + protected virtual void SmoothFollowPhysicsCopy() + { + // hard follow: + // predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); + // tf.SetPositionAndRotation(physicsPosition, physicsRotation); + + // ORIGINAL VERSION: CLEAN AND SIMPLE + /* + // if we are further than N colliders sizes behind, then teleport + float colliderSize = physicsCopyCollider.bounds.size.magnitude; + float threshold = colliderSize * teleportDistanceMultiplier; + float distance = Vector3.Distance(tf.position, physicsCopyRigidbody.position); + if (distance > threshold) + { + tf.position = physicsCopyRigidbody.position; + tf.rotation = physicsCopyRigidbody.rotation; + Debug.Log($"[PredictedRigidbody] Teleported because distance to physics copy = {distance:F2} > threshold {threshold:F2}"); + return; + } + + // smoothly interpolate to the target position. + // speed relative to how far away we are + float positionStep = distance * positionInterpolationSpeed; + tf.position = Vector3.MoveTowards(tf.position, physicsCopyRigidbody.position, positionStep * Time.deltaTime); + + // smoothly interpolate to the target rotation. + // Quaternion.RotateTowards doesn't seem to work at all, so let's use SLerp. + tf.rotation = Quaternion.Slerp(tf.rotation, physicsCopyRigidbody.rotation, rotationInterpolationSpeed * Time.deltaTime); + */ + + // FAST VERSION: this shows in profiler a lot, so cache EVERYTHING! + tf.GetPositionAndRotation(out Vector3 currentPosition, out Quaternion currentRotation); // faster than tf.position + tf.rotation + predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); // faster than Rigidbody .position and .rotation + float deltaTime = Time.deltaTime; + + // slow and simple version: + // float distance = Vector3.Distance(currentPosition, physicsPosition); + // if (distance > smoothFollowThreshold) + // faster version + Vector3 delta = physicsPosition - currentPosition; + float sqrDistance = Vector3.SqrMagnitude(delta); + float distance = Mathf.Sqrt(sqrDistance); + if (sqrDistance > smoothFollowThresholdSqr) + { + tf.SetPositionAndRotation(physicsPosition, physicsRotation); // faster than .position and .rotation manually + Debug.Log($"[PredictedRigidbody] Teleported because distance to physics copy = {distance:F2} > threshold {smoothFollowThreshold:F2}"); + return; + } + + // smoothly interpolate to the target position. + // speed relative to how far away we are. + // => speed increases by distance² because the further away, the + // sooner we need to catch the fuck up + // float positionStep = (distance * distance) * interpolationSpeed; + float positionStep = distance * positionInterpolationSpeed; + + Vector3 newPosition = MoveTowardsCustom(currentPosition, physicsPosition, delta, sqrDistance, distance, positionStep * deltaTime); + + // smoothly interpolate to the target rotation. + // Quaternion.RotateTowards doesn't seem to work at all, so let's use SLerp. + // Quaternions always need to be normalized in order to be a valid rotation after operations + Quaternion newRotation = Quaternion.Slerp(currentRotation, physicsRotation, rotationInterpolationSpeed * deltaTime).normalized; + + // assign position and rotation together. faster than accessing manually. + tf.SetPositionAndRotation(newPosition, newRotation); + } + + // simple and slow version with MoveTowards, which recalculates delta and delta.sqrMagnitude: + // Vector3 newPosition = Vector3.MoveTowards(currentPosition, physicsPosition, positionStep * deltaTime); + // faster version copied from MoveTowards: + // this increases Prediction Benchmark Client's FPS from 615 -> 640. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Vector3 MoveTowardsCustom( + Vector3 current, + Vector3 target, + Vector3 _delta, // pass this in since we already calculated it + float _sqrDistance, // pass this in since we already calculated it + float _distance, // pass this in since we already calculated it + float maxDistanceDelta) + { + if (_sqrDistance == 0.0 || maxDistanceDelta >= 0.0 && _sqrDistance <= maxDistanceDelta * maxDistanceDelta) + return target; + + float distFactor = maxDistanceDelta / _distance; // unlike Vector3.MoveTowards, we only calculate this once + return new Vector3( + // current.x + (_delta.x / _distance) * maxDistanceDelta, + // current.y + (_delta.y / _distance) * maxDistanceDelta, + // current.z + (_delta.z / _distance) * maxDistanceDelta); + current.x + _delta.x * distFactor, + current.y + _delta.y * distFactor, + current.z + _delta.z * distFactor); + } + + // destroy visual copy only in OnStopClient(). + // OnDestroy() wouldn't be called for scene objects that are only disabled instead of destroyed. + public override void OnStopClient() + { + DestroyGhosts(); + } + + void UpdateServer() + { + // bandwidth optimization while idle. + if (reduceSendsWhileIdle) + { + // while moving, always sync every frame for immediate corrections. + // while idle, only sync once per second. + // + // we still need to sync occasionally because objects on client + // may still slide or move slightly due to gravity, physics etc. + // and those still need to get corrected if not moving on server. + // + // TODO + // next round of optimizations: if client received nothing for 1s, + // force correct to last received state. then server doesn't need + // to send once per second anymore. + syncInterval = IsMoving() ? 0 : 1; + } + + // always set dirty to always serialize in next sync interval. + SetDirty(); + } + + // movement detection is virtual, in case projects want to use other methods. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual bool IsMoving() => + // straight forward implementation + // predictedRigidbody.velocity.magnitude >= motionSmoothingVelocityThreshold || + // predictedRigidbody.angularVelocity.magnitude >= motionSmoothingAngularVelocityThreshold; + // faster implementation with cached ² +#if UNITY_6000_0_OR_NEWER + predictedRigidbody.linearVelocity.sqrMagnitude >= motionSmoothingVelocityThresholdSqr || +#else + predictedRigidbody.velocity.sqrMagnitude >= motionSmoothingVelocityThresholdSqr || +#endif + predictedRigidbody.angularVelocity.sqrMagnitude >= motionSmoothingAngularVelocityThresholdSqr; + // TODO maybe merge the IsMoving() checks & callbacks with UpdateState(). + void UpdateGhosting() + { + // perf: enough to check ghosts every few frames. + // PredictionBenchmark: only checking every 4th frame: 585 => 600 FPS + if (Time.frameCount % checkGhostsEveryNthFrame != 0) return; + + // client only uses ghosts on demand while interacting. + // this way 1000 GameObjects don't need +1000 Ghost GameObjects all the time! + + // no ghost at the moment + if (physicsCopy == null) + { + // faster than velocity threshold? then create the ghosts. + // with 10% buffer zone so we don't flip flop all the time. + if (IsMoving()) + { + CreateGhosts(); + OnBeginPrediction(); + } + } + // ghosting at the moment + else + { + // always set last moved time while moving. + // this way we can avoid on/off/oneffects when stopping. + if (IsMoving()) + { + motionSmoothingLastMovedTime = NetworkTime.time; + } + // slower than velocity threshold? then destroy the ghosts. + // with a minimum time since starting to move, to avoid on/off/on effects. + else + { + if (NetworkTime.time >= motionSmoothingLastMovedTime + motionSmoothingTimeTolerance) + { + DestroyGhosts(); + OnEndPrediction(); + physicsCopy = null; // TESTING + } + } + } + } + + // when using Fast mode, we don't create any ghosts. + // but we still want to check IsMoving() in order to support the same + // user callbacks. + bool lastMoving = false; + void UpdateState() + { + // perf: enough to check ghosts every few frames. + // PredictionBenchmark: only checking every 4th frame: 770 => 800 FPS + if (Time.frameCount % checkGhostsEveryNthFrame != 0) return; + + bool moving = IsMoving(); + + // started moving? + if (moving && !lastMoving) + { + OnBeginPrediction(); + lastMoving = true; + } + // stopped moving? + else if (!moving && lastMoving) + { + // ensure a minimum time since starting to move, to avoid on/off/on effects. + if (NetworkTime.time >= motionSmoothingLastMovedTime + motionSmoothingTimeTolerance) + { + OnEndPrediction(); + lastMoving = false; + } + } + } + + void Update() + { + if (isServer) UpdateServer(); + if (isClientOnly) + { + if (mode == PredictionMode.Smooth) + UpdateGhosting(); + else if (mode == PredictionMode.Fast) + UpdateState(); + } + } + + void LateUpdate() + { + // only follow on client-only, not in server or host mode + if (isClientOnly && mode == PredictionMode.Smooth && physicsCopy) SmoothFollowPhysicsCopy(); + } + + void FixedUpdate() + { + // on clients (not host) we record the current state every FixedUpdate. + // this is cheap, and allows us to keep a dense history. + if (!isClientOnly) return; + + // OPTIMIZATION: RecordState() is expensive because it inserts into a SortedList. + // only record if state actually changed! + // risks not having up to date states when correcting, + // but it doesn't matter since we'll always compare with the 'newest' anyway. + // + // we check in here instead of in RecordState() because RecordState() should definitely record if we call it! + if (onlyRecordChanges) + { + // TODO maybe don't reuse the correction thresholds? + tf.GetPositionAndRotation(out Vector3 position, out Quaternion rotation); + // clean & simple: + // if (Vector3.Distance(lastRecorded.position, position) < positionCorrectionThreshold && + // Quaternion.Angle(lastRecorded.rotation, rotation) < rotationCorrectionThreshold) + // faster: + if ((lastRecorded.position - position).sqrMagnitude < positionCorrectionThresholdSqr && + Quaternion.Angle(lastRecorded.rotation, rotation) < rotationCorrectionThreshold) + { + // Debug.Log($"FixedUpdate for {name}: taking optimized early return instead of recording state."); + return; + } + } + + RecordState(); + } + + // manually store last recorded so we can easily check against this + // without traversing the SortedList. + RigidbodyState lastRecorded; + double lastRecordTime; + void RecordState() + { + // performance optimization: only call NetworkTime.time getter once + double networkTime = NetworkTime.time; + + // instead of recording every fixedupdate, let's record in an interval. + // we don't want to record every tiny move and correct too hard. + if (networkTime < lastRecordTime + recordInterval) return; + lastRecordTime = networkTime; + + // NetworkTime.time is always behind by bufferTime. + // prediction aims to be on the exact same server time (immediately). + // use predictedTime to record state, otherwise we would record in the past. + double predictedTime = NetworkTime.predictedTime; + + // FixedUpdate may run twice in the same frame / NetworkTime.time. + // for now, simply don't record if already recorded there. + // previously we checked ContainsKey which is O(logN) for SortedList + // if (stateHistory.ContainsKey(predictedTime)) + // return; + // instead, simply store the last recorded time and don't insert if same. + if (predictedTime == lastRecorded.timestamp) return; + + // keep state history within limit + if (stateHistory.Count >= stateHistoryLimit) + stateHistory.RemoveAt(0); + + // grab current position/rotation/velocity only once. + // this is performance critical, avoid calling .transform multiple times. + tf.GetPositionAndRotation(out Vector3 currentPosition, out Quaternion currentRotation); // faster than accessing .position + .rotation manually +#if UNITY_6000_0_OR_NEWER + Vector3 currentVelocity = predictedRigidbody.linearVelocity; +#else + Vector3 currentVelocity = predictedRigidbody.velocity; +#endif + Vector3 currentAngularVelocity = predictedRigidbody.angularVelocity; + + // calculate delta to previous state (if any) + Vector3 positionDelta = Vector3.zero; + Vector3 velocityDelta = Vector3.zero; + Vector3 angularVelocityDelta = Vector3.zero; + Quaternion rotationDelta = Quaternion.identity; + int stateHistoryCount = stateHistory.Count; // perf: only grab .Count once + if (stateHistoryCount > 0) + { + RigidbodyState last = stateHistory.Values[stateHistoryCount - 1]; + positionDelta = currentPosition - last.position; + velocityDelta = currentVelocity - last.velocity; + // Quaternions always need to be normalized in order to be valid rotations after operations + rotationDelta = (currentRotation * Quaternion.Inverse(last.rotation)).normalized; + angularVelocityDelta = currentAngularVelocity - last.angularVelocity; + + // debug draw the recorded state + // Debug.DrawLine(last.position, currentPosition, Color.red, lineTime); + } + + // create state to insert + RigidbodyState state = new RigidbodyState( + predictedTime, + positionDelta, + currentPosition, + rotationDelta, + currentRotation, + velocityDelta, + currentVelocity, + angularVelocityDelta, + currentAngularVelocity + ); + + // add state to history + stateHistory.Add(predictedTime, state); + + // manually remember last inserted state for faster .Last comparisons + lastRecorded = state; + } + + // optional user callbacks, in case people need to know about events. + protected virtual void OnSnappedIntoPlace() {} + protected virtual void OnBeforeApplyState() {} + protected virtual void OnCorrected() {} + protected virtual void OnBeginPrediction() {} // when the Rigidbody moved above threshold and we created a ghost + protected virtual void OnEndPrediction() {} // when the Rigidbody came to rest and we destroyed the ghost + + void ApplyState(double timestamp, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity) + { + // fix rigidbodies seemingly dancing in place instead of coming to rest. + // hard snap to the position below a threshold velocity. + // this is fine because the visual object still smoothly interpolates to it. + // => consider both velocity and angular velocity (in case of Rigidbodies only rotating with joints etc.) +#if UNITY_6000_0_OR_NEWER + if (predictedRigidbody.linearVelocity.magnitude <= snapThreshold && + predictedRigidbody.angularVelocity.magnitude <= snapThreshold) +#else + if (predictedRigidbody.velocity.magnitude <= snapThreshold && + predictedRigidbody.angularVelocity.magnitude <= snapThreshold) +#endif + { + // Debug.Log($"Prediction: snapped {name} into place because velocity {predictedRigidbody.velocity.magnitude:F3} <= {snapThreshold:F3}"); + + // apply server state immediately. + // important to apply velocity as well, instead of Vector3.zero. + // in case an object is still slightly moving, we don't want it + // to stop and start moving again on client - slide as well here. + predictedRigidbody.position = position; + predictedRigidbody.rotation = rotation; + // projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error + if (!predictedRigidbody.isKinematic) + { +#if UNITY_6000_0_OR_NEWER + predictedRigidbody.linearVelocity = velocity; +#else + predictedRigidbody.velocity = velocity; +#endif + predictedRigidbody.angularVelocity = angularVelocity; + } + + // clear history and insert the exact state we just applied. + // this makes future corrections more accurate. + stateHistory.Clear(); + stateHistory.Add(timestamp, new RigidbodyState( + timestamp, + Vector3.zero, + position, + Quaternion.identity, + rotation, + Vector3.zero, + velocity, + Vector3.zero, + angularVelocity + )); + + // user callback + OnSnappedIntoPlace(); + return; + } + + // we have a callback for snapping into place (above). + // we also need one for corrections without snapping into place. + // call it before applying pos/rot/vel in case we need to set kinematic etc. + OnBeforeApplyState(); + + // apply the state to the Rigidbody + if (mode == PredictionMode.Smooth) + { + // Smooth mode separates Physics from Renderering. + // Rendering smoothly follows Physics in SmoothFollowPhysicsCopy(). + // this allows us to be able to hard teleport to the correction. + // which gives most accurate results since the Rigidbody can't + // be stopped by another object when trying to correct. + predictedRigidbody.position = position; + predictedRigidbody.rotation = rotation; + } + else if (mode == PredictionMode.Fast) + { + // Fast mode doesn't separate physics from rendering. + // The only smoothing we get is from Rigidbody.MovePosition. + predictedRigidbody.MovePosition(position); + predictedRigidbody.MoveRotation(rotation); + } + + // there's only one way to set velocity. + // (projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error) + if (!predictedRigidbody.isKinematic) + { +#if UNITY_6000_0_OR_NEWER + predictedRigidbody.linearVelocity = velocity; +#else + predictedRigidbody.velocity = velocity; +#endif + predictedRigidbody.angularVelocity = angularVelocity; + } + } + + // process a received server state. + // compares it against our history and applies corrections if needed. + void OnReceivedState(double timestamp, RigidbodyState state)//, bool sleeping) + { + // always update remote state ghost + if (remoteCopy != null) + { + Transform remoteCopyTransform = remoteCopy.transform; + remoteCopyTransform.SetPositionAndRotation(state.position, state.rotation); // faster than .position + .rotation setters + remoteCopyTransform.localScale = tf.lossyScale; // world scale! see CreateGhosts comment. + } + + + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // color code remote sleeping objects to debug objects coming to rest + // if (showRemoteSleeping) + // { + // rend.material.color = sleeping ? Color.gray : originalColor; + // } + + // performance: get Rigidbody position & rotation only once, + // and together via its transform + predictedRigidbodyTransform.GetPositionAndRotation(out Vector3 physicsPosition, out Quaternion physicsRotation); + + // OPTIONAL performance optimization when comparing idle objects. + // even idle objects will have a history of ~32 entries. + // sampling & traversing through them is unnecessarily costly. + // instead, compare directly against the current rigidbody position! + // => this is technically not 100% correct if an object runs in + // circles where it may revisit the same position twice. + // => but practically, objects that didn't move will have their + // whole history look like the last inserted state. + // => comparing against that is free and gives us a significant + // performance saving vs. a tiny chance of incorrect results due + // to objects running in circles. + // => the RecordState() call below is expensive too, so we want to + // do this before even recording the latest state. the only way + // to do this (in case last recorded state is too old), is to + // compare against live rigidbody.position without any recording. + // this is as fast as it gets for skipping idle objects. + // + // if this ever causes issues, feel free to disable it. + float positionToStateDistanceSqr = Vector3.SqrMagnitude(state.position - physicsPosition); + if (compareLastFirst && + // Vector3.Distance(state.position, physicsPosition) < positionCorrectionThreshold && // slow comparison + positionToStateDistanceSqr < positionCorrectionThresholdSqr && // fast comparison + Quaternion.Angle(state.rotation, physicsRotation) < rotationCorrectionThreshold) + { + // Debug.Log($"OnReceivedState for {name}: taking optimized early return!"); + return; + } + + // we only capture state every 'interval' milliseconds. + // so the newest entry in 'history' may be up to 'interval' behind 'now'. + // if there's no latency, we may receive a server state for 'now'. + // sampling would fail, if we haven't recorded anything in a while. + // to solve this, always record the current state when receiving a server state. + RecordState(); + + // correction requires at least 2 existing states for 'before' and 'after'. + // if we don't have two yet, drop this state and try again next time once we recorded more. + if (stateHistory.Count < 2) return; + + RigidbodyState oldest = stateHistory.Values[0]; + RigidbodyState newest = stateHistory.Values[stateHistory.Count - 1]; + + // edge case: is the state older than the oldest state in history? + // this can happen if the client gets so far behind the server + // that it doesn't have a recored history to sample from. + // in that case, we should hard correct the client. + // otherwise it could be out of sync as long as it's too far behind. + if (state.timestamp < oldest.timestamp) + { + // when starting, client may only have 2-3 states in history. + // it's expected that server states would be behind those 2-3. + // only show a warning if it's behind the full history limit! + if (stateHistory.Count >= stateHistoryLimit) + Debug.LogWarning($"Hard correcting client object {name} because the client is too far behind the server. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This would cause the client to be out of sync as long as it's behind."); + + // force apply the state + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + return; + } + + // edge case: is it newer than the newest state in history? + // this can happen if client's predictedTime predicts too far ahead of the server. + // in that case, log a warning for now but still apply the correction. + // otherwise it could be out of sync as long as it's too far ahead. + // + // for example, when running prediction on the same machine with near zero latency. + // when applying corrections here, this looks just fine on the local machine. + if (newest.timestamp < state.timestamp) + { + // the correction is for a state in the future. + // we clamp it to 'now'. + // but only correct if off by threshold. + // TODO maybe we should interpolate this back to 'now'? + // if (Vector3.Distance(state.position, physicsPosition) >= positionCorrectionThreshold) // slow comparison + if (positionToStateDistanceSqr >= positionCorrectionThresholdSqr) // fast comparison + { + // this can happen a lot when latency is ~0. logging all the time allocates too much and is too slow. + // double ahead = state.timestamp - newest.timestamp; + // Debug.Log($"Hard correction because the client is ahead of the server by {(ahead*1000):F1}ms. History of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This can happen when latency is near zero, and is fine unless it shows jitter."); + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + } + return; + } + + // find the two closest client states between timestamp + if (!Prediction.Sample(stateHistory, timestamp, out RigidbodyState before, out RigidbodyState after, out int afterIndex, out double t)) + { + // something went very wrong. sampling should've worked. + // hard correct to recover the error. + Debug.LogError($"Failed to sample history of size={stateHistory.Count} @ t={timestamp:F3} oldest={oldest.timestamp:F3} newest={newest.timestamp:F3}. This should never happen because the timestamp is within history."); + ApplyState(state.timestamp, state.position, state.rotation, state.velocity, state.angularVelocity); + return; + } + + // interpolate between them to get the best approximation + RigidbodyState interpolated = RigidbodyState.Interpolate(before, after, (float)t); + + // calculate the difference between where we were and where we should be + // TODO only position for now. consider rotation etc. too later + // float positionToInterpolatedDistance = Vector3.Distance(state.position, interpolated.position); // slow comparison + float positionToInterpolatedDistanceSqr = Vector3.SqrMagnitude(state.position - interpolated.position); // fast comparison + float rotationToInterpolatedDistance = Quaternion.Angle(state.rotation, interpolated.rotation); + // Debug.Log($"Sampled history of size={stateHistory.Count} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3} / {correctionThreshold:F3}"); + + // too far off? then correct it + if (positionToInterpolatedDistanceSqr >= positionCorrectionThresholdSqr || // fast comparison + //positionToInterpolatedDistance >= positionCorrectionThreshold || // slow comparison + rotationToInterpolatedDistance >= rotationCorrectionThreshold) + { + // Debug.Log($"CORRECTION NEEDED FOR {name} @ {timestamp:F3}: client={interpolated.position} server={state.position} difference={difference:F3}"); + + // show the received correction position + velocity for debugging. + // helps to compare with the interpolated/applied correction locally. + //Debug.DrawLine(state.position, state.position + state.velocity * 0.1f, Color.white, lineTime); + + // insert the correction and correct the history on top of it. + // returns the final recomputed state after rewinding. + RigidbodyState recomputed = Prediction.CorrectHistory(stateHistory, stateHistoryLimit, state, before, after, afterIndex); + + // log, draw & apply the final position. + // always do this here, not when iterating above, in case we aren't iterating. + // for example, on same machine with near zero latency. + // int correctedAmount = stateHistory.Count - afterIndex; + // Debug.Log($"Correcting {name}: {correctedAmount} / {stateHistory.Count} states to final position from: {rb.position} to: {last.position}"); + //Debug.DrawLine(physicsCopyRigidbody.position, recomputed.position, Color.green, lineTime); + ApplyState(recomputed.timestamp, recomputed.position, recomputed.rotation, recomputed.velocity, recomputed.angularVelocity); + + // user callback + OnCorrected(); + } + } + + // send state to clients every sendInterval. + // reliable for now. + // TODO we should use the one from FixedUpdate + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + // Time.time was at the beginning of this frame. + // NetworkLateUpdate->Broadcast->OnSerialize is at the end of the frame. + // as result, client should use this to correct the _next_ frame. + // otherwise we see noticeable resets that seem off by one frame. + // + // to solve this, we can send the current deltaTime. + // server is technically supposed to be at a fixed frame rate, but this can vary. + // sending server's current deltaTime is the safest option. + // client then applies it on top of remoteTimestamp. + + + // FAST VERSION: this shows in profiler a lot, so cache EVERYTHING! + tf.GetPositionAndRotation(out Vector3 position, out Quaternion rotation); // faster than tf.position + tf.rotation. server's rigidbody is on the same transform. + + // simple but slow write: + // writer.WriteFloat(Time.deltaTime); + // writer.WriteVector3(position); + // writer.WriteQuaternion(rotation); + // writer.WriteVector3(predictedRigidbody.velocity); + // writer.WriteVector3(predictedRigidbody.angularVelocity); + + // performance optimization: write a whole struct at once via blittable: + PredictedSyncData data = new PredictedSyncData( + Time.deltaTime, + position, + rotation, +#if UNITY_6000_0_OR_NEWER + predictedRigidbody.linearVelocity, +#else + predictedRigidbody.velocity, +#endif + predictedRigidbody.angularVelocity);//, + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // predictedRigidbody.IsSleeping()); + writer.WritePredictedSyncData(data); + } + + // read the server's state, compare with client state & correct if necessary. + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + // deserialize data + // we want to know the time on the server when this was sent, which is remoteTimestamp. + double timestamp = NetworkClient.connection.remoteTimeStamp; + + // simple but slow read: + // double serverDeltaTime = reader.ReadFloat(); + // Vector3 position = reader.ReadVector3(); + // Quaternion rotation = reader.ReadQuaternion(); + // Vector3 velocity = reader.ReadVector3(); + // Vector3 angularVelocity = reader.ReadVector3(); + + // performance optimization: read a whole struct at once via blittable: + PredictedSyncData data = reader.ReadPredictedSyncData(); + double serverDeltaTime = data.deltaTime; + Vector3 position = data.position; + Quaternion rotation = data.rotation; + Vector3 velocity = data.velocity; + Vector3 angularVelocity = data.angularVelocity; + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // bool sleeping = data.sleeping != 0; + + // server sends state at the end of the frame. + // parse and apply the server's delta time to our timestamp. + // otherwise we see noticeable resets that seem off by one frame. + timestamp += serverDeltaTime; + + // however, adding yet one more frame delay gives much(!) better results. + // we don't know why yet, so keep this as an option for now. + // possibly because client captures at the beginning of the frame, + // with physics happening at the end of the frame? + if (oneFrameAhead) timestamp += serverDeltaTime; + + // process received state + OnReceivedState(timestamp, new RigidbodyState(timestamp, Vector3.zero, position, Quaternion.identity, rotation, Vector3.zero, velocity, Vector3.zero, angularVelocity));//, sleeping); + } + + protected override void OnValidate() + { + base.OnValidate(); + + // force syncDirection to be ServerToClient + syncDirection = SyncDirection.ServerToClient; + + // state should be synced immediately for now. + // later when we have prediction fully dialed in, + // then we can maybe relax this a bit. + syncInterval = 0; + } + + // helper function for Physics tests to check if a Rigidbody belongs to + // a PredictedRigidbody component (either on it, or on its ghost). + public static bool IsPredicted(Rigidbody rb, out PredictedRigidbody predictedRigidbody) + { + // by default, Rigidbody is on the PredictedRigidbody GameObject + if (rb.TryGetComponent(out predictedRigidbody)) + return true; + + // it might be on a ghost while interacting + if (rb.TryGetComponent(out PredictedRigidbodyPhysicsGhost ghost)) + { + predictedRigidbody = ghost.target.GetComponent(); + return true; + } + + // otherwise the Rigidbody does not belong to any PredictedRigidbody. + predictedRigidbody = null; + return false; + } + + // helper function for Physics tests to check if a Collider (which may be in children) belongs to + // a PredictedRigidbody component (either on it, or on its ghost). + public static bool IsPredicted(Collider co, out PredictedRigidbody predictedRigidbody) + { + // by default, Collider is on the PredictedRigidbody GameObject or it's children. + predictedRigidbody = co.GetComponentInParent(); + if (predictedRigidbody != null) + return true; + + // it might be on a ghost while interacting + PredictedRigidbodyPhysicsGhost ghost = co.GetComponentInParent(); + if (ghost != null && ghost.target != null && ghost.target.TryGetComponent(out predictedRigidbody)) + return true; + + // otherwise the Rigidbody does not belong to any PredictedRigidbody. + predictedRigidbody = null; + return false; + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta new file mode 100644 index 0000000..1a3ed44 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: d38927cdc6024b9682b5fe9778b9ef99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320, + type: 2} + - remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776, + type: 2} + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbody.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs new file mode 100644 index 0000000..f28d49f --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs @@ -0,0 +1,15 @@ +// Prediction moves out the Rigidbody & Collider into a separate object. +// this component simply points back to the owner component. +// in case Raycasts hit it and need to know the owner, etc. +using UnityEngine; + +namespace Mirror +{ + public class PredictedRigidbodyPhysicsGhost : MonoBehaviour + { + // this is performance critical, so store target's .Transform instead of + // PredictedRigidbody, this way we don't need to call the .transform getter. + [Tooltip("The predicted rigidbody owner.")] + public Transform target; + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta new file mode 100644 index 0000000..19f13c2 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 25593abc9bf0d44878a4ad6018204061 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyPhysicsGhost.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs new file mode 100644 index 0000000..636f397 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs @@ -0,0 +1 @@ +// removed 2024-02-09 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta new file mode 100644 index 0000000..22d9cf0 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 62e7e9424c7e48d69b6a3517796142a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedRigidbodyRemoteGhost.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs new file mode 100644 index 0000000..fa652fd --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs @@ -0,0 +1,54 @@ +// this struct exists only for OnDe/Serialize performance. +// instead of WriteVector3+Quaternion+Vector3+Vector3, +// we read & write the whole struct as blittable once. +// +// struct packing can cause odd results with blittable on different platforms, +// so this is usually not recommended! +// +// in this case however, we need to squeeze everything we can out of prediction +// to support low even devices / VR. +using System.Runtime.InteropServices; +using UnityEngine; + +namespace Mirror +{ + // struct packing + + [StructLayout(LayoutKind.Sequential)] // explicitly force sequential + public struct PredictedSyncData + { + public float deltaTime; // 4 bytes (word aligned) + public Vector3 position; // 12 bytes (word aligned) + public Quaternion rotation; // 16 bytes (word aligned) + public Vector3 velocity; // 12 bytes (word aligned) + public Vector3 angularVelocity; // 12 bytes (word aligned) + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // public byte sleeping; // 1 byte: bool isn't blittable + + // constructor for convenience + public PredictedSyncData(float deltaTime, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)//, bool sleeping) + { + this.deltaTime = deltaTime; + this.position = position; + this.rotation = rotation; + this.velocity = velocity; + this.angularVelocity = angularVelocity; + // DO NOT SYNC SLEEPING! this cuts benchmark performance in half(!!!) + // this.sleeping = sleeping ? (byte)1 : (byte)0; + } + } + + // NetworkReader/Writer extensions to write this struct + public static class PredictedSyncDataReadWrite + { + public static void WritePredictedSyncData(this NetworkWriter writer, PredictedSyncData data) + { + writer.WriteBlittable(data); + } + + public static PredictedSyncData ReadPredictedSyncData(this NetworkReader reader) + { + return reader.ReadBlittable(); + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta new file mode 100644 index 0000000..8a7fe10 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f595f112a39e4634b670d56991b23823 +timeCreated: 1710387026 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictedSyncData.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs new file mode 100644 index 0000000..82945c9 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs @@ -0,0 +1,430 @@ +// standalone utility functions for PredictedRigidbody component. +using System; +using UnityEngine; + +namespace Mirror +{ + public static class PredictionUtils + { + // rigidbody /////////////////////////////////////////////////////////// + // move a Rigidbody + settings from one GameObject to another. + public static void MoveRigidbody(GameObject source, GameObject destination, bool destroySource = true) + { + // create a new Rigidbody component on destination. + // note that adding a Joint automatically adds a Rigidbody. + // so first check if one was added yet. + Rigidbody original = source.GetComponent(); + if (original == null) throw new Exception($"Prediction: attempted to move {source}'s Rigidbody to the predicted copy, but there was no component."); + Rigidbody rigidbodyCopy; + if (!destination.TryGetComponent(out rigidbodyCopy)) + rigidbodyCopy = destination.AddComponent(); + + // copy all properties + rigidbodyCopy.mass = original.mass; +#if UNITY_6000_0_OR_NEWER + rigidbodyCopy.linearDamping = original.linearDamping; + rigidbodyCopy.angularDamping = original.angularDamping; +#else + rigidbodyCopy.drag = original.drag; + rigidbodyCopy.angularDrag = original.angularDrag; +#endif + rigidbodyCopy.useGravity = original.useGravity; + rigidbodyCopy.isKinematic = original.isKinematic; + rigidbodyCopy.interpolation = original.interpolation; + rigidbodyCopy.collisionDetectionMode = original.collisionDetectionMode; + // fix: need to set freezeRotation before constraints: + // https://github.com/MirrorNetworking/Mirror/pull/3946 + rigidbodyCopy.freezeRotation = original.freezeRotation; + rigidbodyCopy.constraints = original.constraints; + rigidbodyCopy.sleepThreshold = original.sleepThreshold; + + // moving (Configurable)Joints messes up their range of motion unless + // we reset to initial position first (we do this in PredictedRigibody.cs). + // so here we don't set the Rigidbody's physics position at all. + // rigidbodyCopy.position = original.position; + // rigidbodyCopy.rotation = original.rotation; + + // projects may keep Rigidbodies as kinematic sometimes. in that case, setting velocity would log an error + if (!original.isKinematic) + { +#if UNITY_6000_0_OR_NEWER + rigidbodyCopy.linearVelocity = original.linearVelocity; +#else + rigidbodyCopy.velocity = original.velocity; +#endif + rigidbodyCopy.angularVelocity = original.angularVelocity; + } + + // destroy original + if (destroySource) GameObject.Destroy(original); + } + + // helper function: if a collider is on a child, copy that child first. + // this way child's relative position/rotation/scale are preserved. + public static GameObject CopyRelativeTransform(GameObject source, Transform sourceChild, GameObject destination) + { + // is this on the source root? then we want to put it on the destination root. + if (sourceChild == source.transform) return destination; + + // is this on a child? then create the same child with the same transform on destination. + // note this is technically only correct for the immediate child since + // .localPosition is relative to parent, but this is good enough. + GameObject child = new GameObject(sourceChild.name); + child.transform.SetParent(destination.transform, true); + child.transform.localPosition = sourceChild.localPosition; + child.transform.localRotation = sourceChild.localRotation; + child.transform.localScale = sourceChild.localScale; + + // assign the same Layer for the physics copy. + // games may use a custom physics collision matrix, layer matters. + child.layer = sourceChild.gameObject.layer; + + return child; + } + + // colliders /////////////////////////////////////////////////////////// + // move all BoxColliders + settings from one GameObject to another. + public static void MoveBoxColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + BoxCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (BoxCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + BoxCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.size = sourceCollider.size; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all SphereColliders + settings from one GameObject to another. + public static void MoveSphereColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + SphereCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (SphereCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + SphereCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.radius = sourceCollider.radius; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all CapsuleColliders + settings from one GameObject to another. + public static void MoveCapsuleColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + CapsuleCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (CapsuleCollider sourceCollider in sourceColliders) + { + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + CapsuleCollider colliderCopy = target.AddComponent(); + colliderCopy.center = sourceCollider.center; + colliderCopy.radius = sourceCollider.radius; + colliderCopy.height = sourceCollider.height; + colliderCopy.direction = sourceCollider.direction; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all MeshColliders + settings from one GameObject to another. + public static void MoveMeshColliders(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + MeshCollider[] sourceColliders = source.GetComponentsInChildren(); + foreach (MeshCollider sourceCollider in sourceColliders) + { + // when Models have Mesh->Read/Write disabled, it means that Unity + // uploads the mesh directly to the GPU and erases it on the CPU. + // on some platforms this makes moving a MeshCollider in builds impossible: + // + // "CollisionMeshData couldn't be created because the mesh has been marked as non-accessible." + // + // on other platforms, this works fine. + // let's show an explicit log message so in case collisions don't + // work at runtime, it's obvious why it happens and how to fix it. + if (!sourceCollider.sharedMesh.isReadable) + { + Debug.Log($"[Prediction]: MeshCollider on {sourceCollider.name} isn't readable, which may indicate that the Mesh only exists on the GPU. If {sourceCollider.name} is missing collisions, then please select the model in the Project Area, and enable Mesh->Read/Write so it's also available on the CPU!"); + // don't early return. keep trying, it may work. + } + + // copy the relative transform: + // if collider is on root, it returns destination root. + // if collider is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceCollider.transform, destination); + MeshCollider colliderCopy = target.AddComponent(); + colliderCopy.sharedMesh = sourceCollider.sharedMesh; + colliderCopy.convex = sourceCollider.convex; + colliderCopy.isTrigger = sourceCollider.isTrigger; + colliderCopy.material = sourceCollider.material; + if (destroySource) GameObject.Destroy(sourceCollider); + } + } + + // move all Colliders + settings from one GameObject to another. + public static void MoveAllColliders(GameObject source, GameObject destination, bool destroySource = true) + { + MoveBoxColliders(source, destination, destroySource); + MoveSphereColliders(source, destination, destroySource); + MoveCapsuleColliders(source, destination, destroySource); + MoveMeshColliders(source, destination, destroySource); + } + + // joints ////////////////////////////////////////////////////////////// + // move all CharacterJoints + settings from one GameObject to another. + public static void MoveCharacterJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + CharacterJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (CharacterJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + CharacterJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.enableProjection = sourceJoint.enableProjection; + jointCopy.highTwistLimit = sourceJoint.highTwistLimit; + jointCopy.lowTwistLimit = sourceJoint.lowTwistLimit; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.projectionAngle = sourceJoint.projectionAngle; + jointCopy.projectionDistance = sourceJoint.projectionDistance; + jointCopy.swing1Limit = sourceJoint.swing1Limit; + jointCopy.swing2Limit = sourceJoint.swing2Limit; + jointCopy.swingAxis = sourceJoint.swingAxis; + jointCopy.swingLimitSpring = sourceJoint.swingLimitSpring; + jointCopy.twistLimitSpring = sourceJoint.twistLimitSpring; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all ConfigurableJoints + settings from one GameObject to another. + public static void MoveConfigurableJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + ConfigurableJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (ConfigurableJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + ConfigurableJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.angularXLimitSpring = sourceJoint.angularXLimitSpring; + jointCopy.angularXDrive = sourceJoint.angularXDrive; + jointCopy.angularXMotion = sourceJoint.angularXMotion; + jointCopy.angularYLimit = sourceJoint.angularYLimit; + jointCopy.angularYMotion = sourceJoint.angularYMotion; + jointCopy.angularYZDrive = sourceJoint.angularYZDrive; + jointCopy.angularYZLimitSpring = sourceJoint.angularYZLimitSpring; + jointCopy.angularZLimit = sourceJoint.angularZLimit; + jointCopy.angularZMotion = sourceJoint.angularZMotion; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.configuredInWorldSpace = sourceJoint.configuredInWorldSpace; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.highAngularXLimit = sourceJoint.highAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs + jointCopy.linearLimitSpring = sourceJoint.linearLimitSpring; + jointCopy.linearLimit = sourceJoint.linearLimit; + jointCopy.lowAngularXLimit = sourceJoint.lowAngularXLimit; // moving this only works if the object is at initial position/rotation/scale, see PredictedRigidbody.cs + jointCopy.massScale = sourceJoint.massScale; + jointCopy.projectionAngle = sourceJoint.projectionAngle; + jointCopy.projectionDistance = sourceJoint.projectionDistance; + jointCopy.projectionMode = sourceJoint.projectionMode; + jointCopy.rotationDriveMode = sourceJoint.rotationDriveMode; + jointCopy.secondaryAxis = sourceJoint.secondaryAxis; + jointCopy.slerpDrive = sourceJoint.slerpDrive; + jointCopy.swapBodies = sourceJoint.swapBodies; + jointCopy.targetAngularVelocity = sourceJoint.targetAngularVelocity; + jointCopy.targetPosition = sourceJoint.targetPosition; + jointCopy.targetRotation = sourceJoint.targetRotation; + jointCopy.targetVelocity = sourceJoint.targetVelocity; + jointCopy.xDrive = sourceJoint.xDrive; + jointCopy.xMotion = sourceJoint.xMotion; + jointCopy.yDrive = sourceJoint.yDrive; + jointCopy.yMotion = sourceJoint.yMotion; + jointCopy.zDrive = sourceJoint.zDrive; + jointCopy.zMotion = sourceJoint.zMotion; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all FixedJoints + settings from one GameObject to another. + public static void MoveFixedJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + FixedJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (FixedJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + FixedJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.massScale = sourceJoint.massScale; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all HingeJoints + settings from one GameObject to another. + public static void MoveHingeJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + HingeJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (HingeJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + HingeJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.limits = sourceJoint.limits; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.motor = sourceJoint.motor; + jointCopy.spring = sourceJoint.spring; + jointCopy.useLimits = sourceJoint.useLimits; + jointCopy.useMotor = sourceJoint.useMotor; + jointCopy.useSpring = sourceJoint.useSpring; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif +#if UNITY_2022_3_OR_NEWER + jointCopy.extendedLimits = sourceJoint.extendedLimits; + jointCopy.useAcceleration = sourceJoint.useAcceleration; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all SpringJoints + settings from one GameObject to another. + public static void MoveSpringJoints(GameObject source, GameObject destination, bool destroySource = true) + { + // colliders may be on children + SpringJoint[] sourceJoints = source.GetComponentsInChildren(); + foreach (SpringJoint sourceJoint in sourceJoints) + { + // copy the relative transform: + // if joint is on root, it returns destination root. + // if joint is on a child, it creates and returns a child on destination. + GameObject target = CopyRelativeTransform(source, sourceJoint.transform, destination); + SpringJoint jointCopy = target.AddComponent(); + // apply settings, in alphabetical order + jointCopy.anchor = sourceJoint.anchor; + jointCopy.autoConfigureConnectedAnchor = sourceJoint.autoConfigureConnectedAnchor; + jointCopy.axis = sourceJoint.axis; + jointCopy.breakForce = sourceJoint.breakForce; + jointCopy.breakTorque = sourceJoint.breakTorque; + jointCopy.connectedAnchor = sourceJoint.connectedAnchor; + jointCopy.connectedBody = sourceJoint.connectedBody; + jointCopy.connectedMassScale = sourceJoint.connectedMassScale; + jointCopy.damper = sourceJoint.damper; + jointCopy.enableCollision = sourceJoint.enableCollision; + jointCopy.enablePreprocessing = sourceJoint.enablePreprocessing; + jointCopy.massScale = sourceJoint.massScale; + jointCopy.maxDistance = sourceJoint.maxDistance; + jointCopy.minDistance = sourceJoint.minDistance; + jointCopy.spring = sourceJoint.spring; + jointCopy.tolerance = sourceJoint.tolerance; +#if UNITY_2020_3_OR_NEWER + jointCopy.connectedArticulationBody = sourceJoint.connectedArticulationBody; +#endif + + if (destroySource) GameObject.Destroy(sourceJoint); + } + } + + // move all Joints + settings from one GameObject to another. + public static void MoveAllJoints(GameObject source, GameObject destination, bool destroySource = true) + { + MoveCharacterJoints(source, destination, destroySource); + MoveConfigurableJoints(source, destination, destroySource); + MoveFixedJoints(source, destination, destroySource); + MoveHingeJoints(source, destination, destroySource); + MoveSpringJoints(source, destination, destroySource); + } + + // all ///////////////////////////////////////////////////////////////// + // move all physics components from one GameObject to another. + public static void MovePhysicsComponents(GameObject source, GameObject destination, bool destroySource = true) + { + // need to move joints first, otherwise we might see: + // 'can't move Rigidbody because a Joint depends on it' + MoveAllJoints(source, destination, destroySource); + MoveAllColliders(source, destination, destroySource); + MoveRigidbody(source, destination, destroySource); + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta new file mode 100644 index 0000000..0c3ac22 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 17cfe1beb3f94a69b94bf60afc37ef7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/PredictionUtils.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat new file mode 100644 index 0000000..d652a50 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat @@ -0,0 +1,85 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RemoteGhostMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.92 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0.09849727, g: 1, b: 0, a: 0.15686275} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta new file mode 100644 index 0000000..ec597ae --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 04f0b2088c857414393bab3b80356776 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/RemoteGhostMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs new file mode 100644 index 0000000..c30ce4a --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs @@ -0,0 +1,60 @@ +// PredictedRigidbody stores a history of its rigidbody states. +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + // inline everything because this is performance critical! + public struct RigidbodyState : PredictedState + { + public double timestamp { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] private set; } + + // we want to store position delta (last + delta = current), and current. + // this way we can apply deltas on top of corrected positions to get the corrected final position. + public Vector3 positionDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this position + public Vector3 position { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Quaternion rotationDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this rotation + public Quaternion rotation { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Vector3 velocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity + public Vector3 velocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public Vector3 angularVelocityDelta { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } // delta to get from last to this velocity + public Vector3 angularVelocity { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; [MethodImpl(MethodImplOptions.AggressiveInlining)] set; } + + public RigidbodyState( + double timestamp, + Vector3 positionDelta, + Vector3 position, + Quaternion rotationDelta, + Quaternion rotation, + Vector3 velocityDelta, + Vector3 velocity, + Vector3 angularVelocityDelta, + Vector3 angularVelocity) + { + this.timestamp = timestamp; + this.positionDelta = positionDelta; + this.position = position; + this.rotationDelta = rotationDelta; + this.rotation = rotation; + this.velocityDelta = velocityDelta; + this.velocity = velocity; + this.angularVelocityDelta = angularVelocityDelta; + this.angularVelocity = angularVelocity; + } + + public static RigidbodyState Interpolate(RigidbodyState a, RigidbodyState b, float t) + { + return new RigidbodyState + { + position = Vector3.Lerp(a.position, b.position, t), + // Quaternions always need to be normalized in order to be a valid rotation after operations + rotation = Quaternion.Slerp(a.rotation, b.rotation, t).normalized, + velocity = Vector3.Lerp(a.velocity, b.velocity, t), + angularVelocity = Vector3.Lerp(a.angularVelocity, b.angularVelocity, t) + }; + } + } +} diff --git a/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta new file mode 100644 index 0000000..593ce27 --- /dev/null +++ b/Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ed0e1c0c874c4c9db6be2d5885bb7bee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/PredictedRigidbody/RigidbodyState.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling.meta b/Assets/Mirror/Components/Profiling.meta new file mode 100644 index 0000000..043fbfe --- /dev/null +++ b/Assets/Mirror/Components/Profiling.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4b799e47369048fcb1604e5b3e7d71cf +timeCreated: 1724245584 diff --git a/Assets/Mirror/Components/Profiling/BaseUIGraph.cs b/Assets/Mirror/Components/Profiling/BaseUIGraph.cs new file mode 100644 index 0000000..94e84e9 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/BaseUIGraph.cs @@ -0,0 +1,217 @@ +using System; +using UnityEngine; +using UnityEngine.Serialization; +using UnityEngine.UI; +namespace Mirror +{ + public enum GraphAggregationMode + { + Sum, + Average, + PerSecond, + Min, + Max + } + + public abstract class BaseUIGraph : MonoBehaviour + { + static readonly int MaxValue = Shader.PropertyToID("_MaxValue"); + static readonly int GraphData = Shader.PropertyToID("_GraphData"); + static readonly int CategoryCount = Shader.PropertyToID("_CategoryCount"); + static readonly int Colors = Shader.PropertyToID("_CategoryColors"); + static readonly int Width = Shader.PropertyToID("_Width"); + static readonly int DataStart = Shader.PropertyToID("_DataStart"); + + public Material Material; + public Graphic Renderer; + [Range(1, 64)] + public int Points = 64; + public float SecondsPerPoint = 1; + public Color[] CategoryColors = new[] { Color.cyan }; + public bool IsStacked; + + public Text[] LegendTexts; + [Header("Diagnostics")] + [ReadOnly, SerializeField] + Material runtimeMaterial; + + float[] graphData; + // graphData is a circular buffer, this is the offset to get the 0-index + int graphDataStartIndex; + // Is graphData dirty and needs to be set to the material + bool isGraphDataDirty; + // currently aggregating data to be added to the graph soon + float[] aggregatingData; + GraphAggregationMode[] aggregatingModes; + // Counts for avg aggregation mode + int[] aggregatingDataCounts; + // How much time has elapsed since the last aggregation finished + float aggregatingTime; + + int DataLastIndex => (graphDataStartIndex - 1 + Points) % Points; + + void Awake() + { + Renderer.material = runtimeMaterial = Instantiate(Material); + graphData = new float[Points * CategoryColors.Length]; + aggregatingData = new float[CategoryColors.Length]; + aggregatingDataCounts = new int[CategoryColors.Length]; + aggregatingModes = new GraphAggregationMode[CategoryColors.Length]; + isGraphDataDirty = true; + } + + protected virtual void OnValidate() + { + if (Renderer == null) + Renderer = GetComponent(); + } + + protected virtual void Update() + { + for (int i = 0; i < CategoryColors.Length; i++) + { + CollectData(i, out float value, out GraphAggregationMode mode); + // we probably don't need negative values, so lets skip supporting it + if (value < 0) + { + Debug.LogWarning("Graphing negative values is not supported."); + value = 0; + } + + if (mode != aggregatingModes[i]) + { + aggregatingModes[i] = mode; + ResetCurrent(i); + } + + switch (mode) + { + case GraphAggregationMode.Average: + case GraphAggregationMode.Sum: + case GraphAggregationMode.PerSecond: + aggregatingData[i] += value; + aggregatingDataCounts[i]++; + break; + case GraphAggregationMode.Min: + if (aggregatingData[i] > value) + aggregatingData[i] = value; + break; + case GraphAggregationMode.Max: + if (value > aggregatingData[i]) + aggregatingData[i] = value; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + aggregatingTime += Time.deltaTime; + if (aggregatingTime > SecondsPerPoint) + { + graphDataStartIndex = (graphDataStartIndex + 1) % Points; + ClearDataAt(DataLastIndex); + for (int i = 0; i < CategoryColors.Length; i++) + { + float value = aggregatingData[i]; + switch (aggregatingModes[i]) + { + case GraphAggregationMode.Sum: + case GraphAggregationMode.Min: + case GraphAggregationMode.Max: + // do nothing! + break; + case GraphAggregationMode.Average: + value /= aggregatingDataCounts[i]; + break; + case GraphAggregationMode.PerSecond: + value /= aggregatingTime; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + SetCurrentGraphData(i, value); + ResetCurrent(i); + } + + aggregatingTime = 0; + } + } + + void ResetCurrent(int i) + { + switch (aggregatingModes[i]) + { + case GraphAggregationMode.Min: + aggregatingData[i] = float.MaxValue; + break; + default: + aggregatingData[i] = 0; + break; + } + + aggregatingDataCounts[i] = 0; + } + + protected virtual string FormatValue(float value) => $"{value:N1}"; + + protected abstract void CollectData(int category, out float value, out GraphAggregationMode mode); + + void SetCurrentGraphData(int c, float value) + { + graphData[DataLastIndex * CategoryColors.Length + c] = value; + isGraphDataDirty = true; + } + + void ClearDataAt(int i) + { + for (int c = 0; c < CategoryColors.Length; c++) + graphData[i * CategoryColors.Length + c] = 0; + + isGraphDataDirty = true; + } + + public void LateUpdate() + { + if (isGraphDataDirty) + { + runtimeMaterial.SetInt(Width, Points); + runtimeMaterial.SetInt(DataStart, graphDataStartIndex); + float max = 1; + if (IsStacked) + for (int x = 0; x < Points; x++) + { + float total = 0; + for (int c = 0; c < CategoryColors.Length; c++) + total += graphData[x * CategoryColors.Length + c]; + + if (total > max) + max = total; + } + else + for (int i = 0; i < graphData.Length; i++) + { + float v = graphData[i]; + if (v > max) + max = v; + } + + max = AdjustMaxValue(max); + for (int i = 0; i < LegendTexts.Length; i++) + { + Text legendText = LegendTexts[i]; + float pct = (float)i / (LegendTexts.Length - 1); + legendText.text = FormatValue(max * pct); + } + + runtimeMaterial.SetFloat(MaxValue, max); + runtimeMaterial.SetFloatArray(GraphData, graphData); + runtimeMaterial.SetInt(CategoryCount, CategoryColors.Length); + runtimeMaterial.SetColorArray(Colors, CategoryColors); + isGraphDataDirty = false; + } + } + + protected virtual float AdjustMaxValue(float max) => Mathf.Ceil(max); + } +} diff --git a/Assets/Mirror/Components/Profiling/BaseUIGraph.cs.meta b/Assets/Mirror/Components/Profiling/BaseUIGraph.cs.meta new file mode 100644 index 0000000..51dab56 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/BaseUIGraph.cs.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: 0f7dbe0fe96842f3b3ec76d05d2bb24a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + - Renderer: {instanceID: 0} + - runtimeMaterial: {instanceID: 0} + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/BaseUIGraph.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs b/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs new file mode 100644 index 0000000..d0f1a86 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs @@ -0,0 +1,40 @@ +using System; +using UnityEngine; +namespace Mirror +{ + public class FpsMinMaxAvgGraph : BaseUIGraph + { + protected override void CollectData(int category, out float value, out GraphAggregationMode mode) + { + value = 1 / Time.deltaTime; + switch (category) + { + case 0: + mode = GraphAggregationMode.Average; + break; + case 1: + mode = GraphAggregationMode.Min; + break; + case 2: + mode = GraphAggregationMode.Max; + break; + default: + throw new ArgumentOutOfRangeException($"{category} is not valid."); + } + } + + protected override void OnValidate() + { + base.OnValidate(); + if (CategoryColors.Length != 3) + CategoryColors = new[] + { + Color.cyan, // avg + Color.red, // min + Color.green // max + }; + + IsStacked = false; + } + } +} diff --git a/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs.meta b/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs.meta new file mode 100644 index 0000000..25af560 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 73bc3b929ec94537a8dbd67eb9d0c2c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/FpsMinMaxAvgGraph.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/LineGraph.mat b/Assets/Mirror/Components/Profiling/LineGraph.mat new file mode 100644 index 0000000..e42a0ce --- /dev/null +++ b/Assets/Mirror/Components/Profiling/LineGraph.mat @@ -0,0 +1,89 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: LineGraph + m_Shader: {fileID: 4800000, guid: e9fd6820072746bbaa3a83a449c31709, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _CategoryCount: 0 + - _ColorMask: 15 + - _Cutoff: 0.5 + - _DataStart: 0 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _LineWidth: 1 + - _MaxValue: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _UVSec: 0 + - _UseUIAlphaClip: 0 + - _Width: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Components/Profiling/LineGraph.mat.meta b/Assets/Mirror/Components/Profiling/LineGraph.mat.meta new file mode 100644 index 0000000..10ff58a --- /dev/null +++ b/Assets/Mirror/Components/Profiling/LineGraph.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5f77111e39fad6240bbf2a93d735b648 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/LineGraph.mat + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs b/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs new file mode 100644 index 0000000..ac2b1fd --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs @@ -0,0 +1,85 @@ +using System; +using UnityEngine; +namespace Mirror +{ + public class NetworkBandwidthGraph : BaseUIGraph + { + int dataIn; + int dataOut; + + void Start() + { + // Ordering, Awake happens before NetworkDiagnostics reset + NetworkDiagnostics.InMessageEvent += OnReceive; + NetworkDiagnostics.OutMessageEvent += OnSend; + } + + void OnEnable() + { + // If we've been inactive, clear counter + dataIn = 0; + dataOut = 0; + } + + void OnDestroy() + { + NetworkDiagnostics.InMessageEvent -= OnReceive; + NetworkDiagnostics.OutMessageEvent -= OnSend; + } + + void OnSend(NetworkDiagnostics.MessageInfo obj) => dataOut += obj.bytes; + + void OnReceive(NetworkDiagnostics.MessageInfo obj) => dataIn += obj.bytes; + + protected override void CollectData(int category, out float value, out GraphAggregationMode mode) + { + mode = GraphAggregationMode.PerSecond; + switch (category) + { + case 0: + value = dataIn; + dataIn = 0; + break; + case 1: + value = dataOut; + dataOut = 0; + break; + default: + throw new ArgumentOutOfRangeException($"{category} is not valid."); + } + } + + static readonly string[] Units = new[] { "B/s", "KiB/s", "MiB/s" }; + const float UnitScale = 1024; + + protected override string FormatValue(float value) + { + string selectedUnit = null; + for (int i = 0; i < Units.Length; i++) + { + string unit = Units[i]; + selectedUnit = unit; + if (i > 0) + value /= UnitScale; + + if (value < UnitScale) + break; + } + + return $"{value:N0} {selectedUnit}"; + } + + protected override void OnValidate() + { + base.OnValidate(); + if (CategoryColors.Length != 2) + CategoryColors = new[] + { + Color.red, // min + Color.green // max + }; + + IsStacked = false; + } + } +} diff --git a/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs.meta b/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs.meta new file mode 100644 index 0000000..adcf9b7 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e1ae19b97f0e4a5eb8cf5158d97506f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/NetworkBandwidthGraph.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader b/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader new file mode 100644 index 0000000..c491953 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader @@ -0,0 +1,178 @@ +Shader "Mirror/NetworkGraphLines" +{ + Properties + { + [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + _Width ("Width", Int) = 0 + _LineWidth ("Line Width", Float) = 0.005 + _CategoryCount ("CategoryCount", Int) = 0 + _MaxValue ("MaxValue", Float) = 1 + _DataStart ("DataStart", Int) = 0 + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest [unity_GUIZTestMode] + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass + { + Name "Default" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + + #pragma multi_compile_local _ UNITY_UI_CLIP_RECT + #pragma multi_compile_local _ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + sampler2D _MainTex; // we dont use this, but unitys ui library expects the shader to have a texture + fixed4 _Color; + fixed4 _TextureSampleAdd; + float4 _ClipRect; + float4 _MainTex_ST; + + uint _Width; + half _LineWidth; + uint _CategoryCount; + uint _MaxValue; + uint _DataStart; + half _GraphData[64 /* max. 128 points */ * 8 /* max 8 categories */]; + half4 _CategoryColors[8 /* max 8 categories */]; + + v2f vert(appdata_t v) + { + v2f OUT; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + OUT.worldPosition = v.vertex; + OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); + + OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + + OUT.color = v.color * _Color; + return OUT; + } + + // Helper function to calculate the shortest distance from a point (p) to a line segment (from a to b) + float distanceToLineSegment(float2 p, float2 a, float2 b) + { + float2 ab = b - a; + float2 ap = p - a; + float t = saturate(dot(ap, ab) / dot(ab, ab)); + // Clamp t between 0 and 1 to ensure we stay within the segment + float2 closestPoint = a + t * ab; // Find the closest point on the line segment + return length(p - closestPoint); // Return the distance from p to the closest point on the line + } + + fixed4 frag(v2f IN) : SV_Target + { + uint wCur = (uint)(IN.texcoord.x * _Width); + uint wMin = wCur == 0 ? 0 : wCur - 1; + uint wMax = wCur == _Width - 1 ? wCur : wCur + 1; + float2 screenSize = _ScreenParams.xy; + // this scaling only works if the object is flat and not rotated - but thats fine + float2 pixelScale = float2(1 / ddx(IN.texcoord.x), 1 / ddy(IN.texcoord.y)); + float2 screenSpaceUV = IN.texcoord * pixelScale; + half4 color = half4(0, 0, 0, 0); + // Loop through the graph's points + bool colored = false; + for (uint wNonOffset = wMin; wNonOffset < wMax && !colored; wNonOffset++) + { + uint w = (wNonOffset + _DataStart) % _Width; + // previous entry, unless it's the start, then we clamp to start + uint nextW = (w + 1) % _Width; + + float texPosCurrentX = float(wNonOffset) / _Width; + float texPosPrevX = texPosCurrentX + 1.0f / _Width; + + + for (uint c = 0; c < _CategoryCount; c++) + { + float categoryValueCurrent = _GraphData[w * _CategoryCount + c] / _MaxValue; + float categoryValueNext = _GraphData[nextW * _CategoryCount + c] / _MaxValue; + + float2 pointCurrent = float2(texPosCurrentX, categoryValueCurrent); + float2 pointNext = float2(texPosPrevX, categoryValueNext); + + float distance = distanceToLineSegment(screenSpaceUV, pointCurrent * pixelScale, + pointNext * pixelScale); + + if (distance < _LineWidth) + { + color = _CategoryColors[c]; + colored = true; + break; + } + } + } + + color *= IN.color; + + #ifdef UNITY_UI_CLIP_RECT + color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); + #endif + + #ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); + #endif + + return color; + } + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader.meta b/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader.meta new file mode 100644 index 0000000..0fcbede --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkGraphLines.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e9fd6820072746bbaa3a83a449c31709 +timeCreated: 1725809505 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/NetworkGraphLines.shader + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader b/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader new file mode 100644 index 0000000..e666d41 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader @@ -0,0 +1,138 @@ +Shader "Mirror/NetworkGraphStacked" +{ + Properties + { + [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + _Width ("Width", Int) = 0 + _CategoryCount ("CategoryCount", Int) = 0 + _MaxValue ("MaxValue", Float) = 1 + _DataStart ("DataStart", Int) = 0 + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest [unity_GUIZTestMode] + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass + { + Name "Default" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + + #pragma multi_compile_local _ UNITY_UI_CLIP_RECT + #pragma multi_compile_local _ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + sampler2D _MainTex; // we dont use this, but unitys ui library expects the shader to have a texture + fixed4 _Color; + fixed4 _TextureSampleAdd; + float4 _ClipRect; + float4 _MainTex_ST; + + uint _Width; + uint _CategoryCount; + uint _MaxValue; + uint _DataStart; + half _GraphData[64 /* max. 64 points */ * 8 /* max 8 categories */]; + half4 _CategoryColors[8 /* max 8 categories */]; + + v2f vert(appdata_t v) + { + v2f OUT; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + OUT.worldPosition = v.vertex; + OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); + + OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + + OUT.color = v.color * _Color; + return OUT; + } + + fixed4 frag(v2f IN) : SV_Target + { + uint w = ((uint)(IN.texcoord.x * _Width) + _DataStart) % _Width; + half4 color = half4(0, 0, 0, 0); + float totalValue = 0; + for (uint c = 0; c < _CategoryCount; c++) + { + float categoryValue = _GraphData[w * _CategoryCount + c] / _MaxValue; + totalValue += categoryValue; + if (totalValue >= IN.texcoord.y) + { + color = _CategoryColors[c]; + break; + } + } + color *= IN.color; + + #ifdef UNITY_UI_CLIP_RECT + color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); + #endif + + #ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); + #endif + + return color; + } + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader.meta b/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader.meta new file mode 100644 index 0000000..2559cf6 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b5b24284f35f4992bcd4cc43919267d7 +timeCreated: 1724246251 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/NetworkGraphStacked.shader + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs b/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs new file mode 100644 index 0000000..bcc1639 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; +namespace Mirror +{ + public class NetworkPingGraph : BaseUIGraph + { + protected override void CollectData(int category, out float value, out GraphAggregationMode mode) + { + mode = GraphAggregationMode.Average; + switch (category) + { + case 0: + value = (float)NetworkTime.rtt * 1000f; + break; + case 1: + value = (float)NetworkTime.rttVariance * 1000f; + break; + default: + throw new ArgumentOutOfRangeException($"{category} is not valid."); + } + } + + protected override string FormatValue(float value) => $"{value:N0}ms"; + + protected override void OnValidate() + { + base.OnValidate(); + if (CategoryColors.Length != 2) + CategoryColors = new[] { Color.cyan, Color.yellow }; + + IsStacked = false; + } + } +} diff --git a/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs.meta b/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs.meta new file mode 100644 index 0000000..4ec56aa --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkPingGraph.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 14a68afedbbf4568b0decc5c3fe6dfd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/NetworkPingGraph.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs b/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs new file mode 100644 index 0000000..fe78918 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Mirror.RemoteCalls; +using UnityEngine; + +namespace Mirror +{ + public class NetworkRuntimeProfiler : MonoBehaviour + { + [Serializable] + public class Sorter : IComparer + { + public SortBy Order; + + public int Compare(Stat a, Stat b) + { + if (a == null) + return 1; + + if (b == null) + return -1; + + // Compare B to A for desc order + switch (Order) + { + case SortBy.RecentBytes: + return b.RecentBytes.CompareTo(a.RecentBytes); + case SortBy.RecentCount: + return b.RecentCount.CompareTo(a.RecentCount); + case SortBy.TotalBytes: + return b.TotalBytes.CompareTo(a.TotalBytes); + case SortBy.TotalCount: + return b.TotalCount.CompareTo(a.TotalCount); + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + public enum SortBy + { + RecentBytes, + RecentCount, + TotalBytes, + TotalCount + } + + public class Stat + { + public string Name; + public long TotalCount; + public long TotalBytes; + + public long RecentCount; + public long RecentBytes; + + public void ResetRecent() + { + RecentCount = 0; + RecentBytes = 0; + } + + public void Add(int count, int bytes) + { + TotalBytes += bytes; + TotalCount += count; + + RecentBytes += bytes; + RecentCount += count; + } + } + + class MessageStats + { + public readonly Dictionary MessageByType = new Dictionary(); + public readonly Dictionary RpcByHash = new Dictionary(); + + public void Record(NetworkDiagnostics.MessageInfo info) + { + Type type = info.message.GetType(); + if (!MessageByType.TryGetValue(type, out Stat stat)) + { + stat = new Stat + { + Name = type.ToString(), + TotalCount = 0, + TotalBytes = 0, + RecentCount = 0, + RecentBytes = 0 + }; + + MessageByType[type] = stat; + } + + stat.Add(info.count, info.bytes * info.count); + + if (info.message is CommandMessage cmd) + RecordRpc(cmd.functionHash, info); + else if (info.message is RpcMessage rpc) + RecordRpc(rpc.functionHash, info); + } + + void RecordRpc(ushort hash, NetworkDiagnostics.MessageInfo info) + { + if (!RpcByHash.TryGetValue(hash, out Stat stat)) + { + string name = "n/a"; + RemoteCallDelegate rpcDelegate = RemoteProcedureCalls.GetDelegate(hash); + if (rpcDelegate != null) + name = $"{rpcDelegate.Method.DeclaringType}.{rpcDelegate.GetMethodName().Replace(RemoteProcedureCalls.InvokeRpcPrefix, "")}"; + + stat = new Stat + { + Name = name, + TotalCount = 0, + TotalBytes = 0, + RecentCount = 0, + RecentBytes = 0 + }; + + RpcByHash[hash] = stat; + } + + stat.Add(info.count, info.bytes * info.count); + } + + public void ResetRecent() + { + foreach (Stat stat in MessageByType.Values) + stat.ResetRecent(); + + foreach (Stat stat in RpcByHash.Values) + stat.ResetRecent(); + } + } + + [Tooltip("How many seconds to accumulate 'recent' stats for, this is also the output interval")] + public float RecentDuration = 5; + public Sorter Sort = new Sorter(); + + public enum OutputType + { + UnityLog, + StdOut, + File + } + + public OutputType Output; + [Tooltip("If Output is set to 'File', where to the path of that file")] + public string OutputFilePath = "network-stats.log"; + + readonly MessageStats inStats = new MessageStats(); + readonly MessageStats outStats = new MessageStats(); + readonly StringBuilder printBuilder = new StringBuilder(); + float elapsedSinceReset; + + void Start() + { + // Ordering, Awake happens before NetworkDiagnostics reset + NetworkDiagnostics.InMessageEvent += HandleMessageIn; + NetworkDiagnostics.OutMessageEvent += HandleMessageOut; + } + + void OnDestroy() + { + NetworkDiagnostics.InMessageEvent -= HandleMessageIn; + NetworkDiagnostics.OutMessageEvent -= HandleMessageOut; + } + + void HandleMessageOut(NetworkDiagnostics.MessageInfo info) => outStats.Record(info); + + void HandleMessageIn(NetworkDiagnostics.MessageInfo info) => inStats.Record(info); + + void LateUpdate() + { + elapsedSinceReset += Time.deltaTime; + if (elapsedSinceReset > RecentDuration) + { + elapsedSinceReset = 0; + Print(); + inStats.ResetRecent(); + outStats.ResetRecent(); + } + } + + void Print() + { + printBuilder.Clear(); + printBuilder.AppendLine($"Stats for {DateTime.Now} ({RecentDuration:N1}s interval)"); + int nameMaxLength = "OUT Message".Length; + + foreach (Stat stat in inStats.MessageByType.Values) + if (stat.Name.Length > nameMaxLength) + nameMaxLength = stat.Name.Length; + + foreach (Stat stat in outStats.MessageByType.Values) + if (stat.Name.Length > nameMaxLength) + nameMaxLength = stat.Name.Length; + + foreach (Stat stat in inStats.RpcByHash.Values) + if (stat.Name.Length > nameMaxLength) + nameMaxLength = stat.Name.Length; + + foreach (Stat stat in outStats.RpcByHash.Values) + if (stat.Name.Length > nameMaxLength) + nameMaxLength = stat.Name.Length; + + string recentBytes = "Recent Bytes"; + string recentCount = "Recent Count"; + string totalBytes = "Total Bytes"; + string totalCount = "Total Count"; + int maxBytesLength = FormatBytes(999999).Length; + int maxCountLength = FormatCount(999999).Length; + + int recentBytesPad = Mathf.Max(recentBytes.Length, maxBytesLength); + int recentCountPad = Mathf.Max(recentCount.Length, maxCountLength); + int totalBytesPad = Mathf.Max(totalBytes.Length, maxBytesLength); + int totalCountPad = Mathf.Max(totalCount.Length, maxCountLength); + string header = $"| {"IN Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; + string sep = "".PadLeft(header.Length, '-'); + printBuilder.AppendLine(sep); + printBuilder.AppendLine(header); + printBuilder.AppendLine(sep); + + foreach (Stat stat in inStats.MessageByType.Values.OrderBy(stat => stat, Sort)) + printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |"); + + header = $"| {"IN RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; + printBuilder.AppendLine(sep); + printBuilder.AppendLine(header); + printBuilder.AppendLine(sep); + foreach (Stat stat in inStats.RpcByHash.Values.OrderBy(stat => stat, Sort)) + printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |"); + + header = $"| {"OUT Message".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; + printBuilder.AppendLine(sep); + printBuilder.AppendLine(header); + printBuilder.AppendLine(sep); + foreach (Stat stat in outStats.MessageByType.Values.OrderBy(stat => stat, Sort)) + printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |"); + + header = $"| {"OUT RPCs".PadLeft(nameMaxLength)} | {recentBytes.PadLeft(recentBytesPad)} | {recentCount.PadLeft(recentCountPad)} | {totalBytes.PadLeft(totalBytesPad)} | {totalCount.PadLeft(totalCountPad)} |"; + printBuilder.AppendLine(sep); + printBuilder.AppendLine(header); + printBuilder.AppendLine(sep); + + foreach (Stat stat in outStats.RpcByHash.Values.OrderBy(stat => stat, Sort)) + printBuilder.AppendLine($"| {stat.Name.PadLeft(nameMaxLength)} | {FormatBytes(stat.RecentBytes).PadLeft(recentBytesPad)} | {FormatCount(stat.RecentCount).PadLeft(recentCountPad)} | {FormatBytes(stat.TotalBytes).PadLeft(totalBytesPad)} | {FormatCount(stat.TotalCount).PadLeft(totalCountPad)} |"); + + printBuilder.AppendLine(sep); + + switch (Output) + { + case OutputType.UnityLog: + Debug.Log(printBuilder.ToString()); + break; + case OutputType.StdOut: + Console.Write(printBuilder); + break; + case OutputType.File: + File.AppendAllText(OutputFilePath, printBuilder.ToString()); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + static string FormatBytes(long bytes) + { + const double KiB = 1024; + const double MiB = KiB * 1024; + const double GiB = MiB * 1024; + const double TiB = GiB * 1024; + + if (bytes < KiB) + return $"{bytes:N0} B"; + + if (bytes < MiB) + return $"{bytes / KiB:N2} KiB"; + + if (bytes < GiB) + return $"{bytes / MiB:N2} MiB"; + + if (bytes < TiB) + return $"{bytes / GiB:N2} GiB"; + + return $"{bytes / TiB:N2} TiB"; + } + + string FormatCount(long count) + { + const double K = 1000; + const double M = K * 1000; + const double G = M * 1000; + const double T = G * 1000; + + if (count < K) + return $"{count:N0}"; + + if (count < M) + return $"{count / K:N2} K"; + + if (count < G) + return $"{count / M:N2} M"; + + if (count < T) + return $"{count / G:N2} G"; + + return $"{count / T:N2} T"; + } + } +} diff --git a/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs.meta b/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs.meta new file mode 100644 index 0000000..6fc7aed --- /dev/null +++ b/Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ef8db82aeb77400bb9e80850e39065a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/NetworkRuntimeProfiler.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/Prefabs.meta b/Assets/Mirror/Components/Profiling/Prefabs.meta new file mode 100644 index 0000000..e81bce5 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 083c6613a11cad746bb252bc7748947f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab b/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab new file mode 100644 index 0000000..5aff497 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab @@ -0,0 +1,1776 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &119935549420283780 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8824290184142807954} + m_Layer: 5 + m_Name: Legend100 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8824290184142807954 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 119935549420283780} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8397968435809926716} + - {fileID: 8383045724353990353} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &215824790723025810 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8473536528693599174} + - component: {fileID: 8359308210431883230} + m_Layer: 5 + m_Name: LegendOUT + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8473536528693599174 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 215824790723025810} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5970650343794535896} + - {fileID: 2927000160895229417} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8359308210431883230 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 215824790723025810} + m_CullTransparentMesh: 1 +--- !u!1 &230788547622420441 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 968396119680197966} + - component: {fileID: 5129519199212594243} + - component: {fileID: 5123833194418803548} + m_Layer: 5 + m_Name: GraphContent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &968396119680197966 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 842792608162333385} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: -20, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5129519199212594243 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_CullTransparentMesh: 1 +--- !u!114 &5123833194418803548 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &969091221012082297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8397968435809926716} + - component: {fileID: 5852067364008015930} + - component: {fileID: 4136376136871219296} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8397968435809926716 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8824290184142807954} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5852067364008015930 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_CullTransparentMesh: 1 +--- !u!114 &4136376136871219296 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1694800138959048866 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5970650343794535896} + - component: {fileID: 3299375740833370906} + - component: {fileID: 6202027950733238712} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5970650343794535896 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8473536528693599174} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3299375740833370906 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_CullTransparentMesh: 1 +--- !u!114 &6202027950733238712 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1711370235648153955 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5455569689841791731} + - component: {fileID: 8443939090520853786} + - component: {fileID: 1177453892628721408} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5455569689841791731 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5885248672530866080} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8443939090520853786 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_CullTransparentMesh: 1 +--- !u!114 &1177453892628721408 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2002525035342291879 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1750250400045347475} + - component: {fileID: 8835486359842310823} + m_Layer: 5 + m_Name: LegendIN + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1750250400045347475 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002525035342291879} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5157207313487273501} + - {fileID: 3683314132040949185} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8835486359842310823 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002525035342291879} + m_CullTransparentMesh: 1 +--- !u!1 &3357588547163078786 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2288491264626255212} + m_Layer: 5 + m_Name: LegendsY + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2288491264626255212 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3357588547163078786} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5885248672530866080} + - {fileID: 5389867435348264296} + - {fileID: 8455135462272940247} + - {fileID: 6309157798075429021} + - {fileID: 8824290184142807954} + m_Father: {fileID: 842792608162333385} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: -20, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &3534129496521135982 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 842792608162333385} + m_Layer: 5 + m_Name: Container + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &842792608162333385 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3534129496521135982} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 968396119680197966} + - {fileID: 2288491264626255212} + - {fileID: 2581675890115619580} + - {fileID: 5071673759804795070} + m_Father: {fileID: 2138752905301465689} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 15, y: 0} + m_SizeDelta: {x: -50, y: -60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &3670180597793129839 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2138752905301465689} + - component: {fileID: 8024388048541391361} + m_Layer: 5 + m_Name: BandwidthGraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2138752905301465689 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3670180597793129839} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3363869356760374277} + - {fileID: 842792608162333385} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &8024388048541391361 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3670180597793129839} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e1ae19b97f0e4a5eb8cf5158d97506f5, type: 3} + m_Name: + m_EditorClassIdentifier: + Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + Renderer: {fileID: 5123833194418803548} + Points: 64 + SecondsPerPoint: 0.5 + CategoryColors: + - {r: 1, g: 0, b: 0, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + IsStacked: 0 + LegendTexts: + - {fileID: 142216866270345907} + - {fileID: 4330748233085529081} + - {fileID: 2248143582364066648} + - {fileID: 97403263534861610} + - {fileID: 4349487955187298716} + runtimeMaterial: {fileID: 0} +--- !u!1 &3678091663373353095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5732919540871248940} + - component: {fileID: 6719434420897279190} + - component: {fileID: 142216866270345907} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5732919540871248940 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5885248672530866080} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6719434420897279190 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_CullTransparentMesh: 1 +--- !u!114 &142216866270345907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &3714570775115803475 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8383045724353990353} + - component: {fileID: 1355767179239727018} + - component: {fileID: 4349487955187298716} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8383045724353990353 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8824290184142807954} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &1355767179239727018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_CullTransparentMesh: 1 +--- !u!114 &4349487955187298716 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &4375453557142464801 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2581675890115619580} + - component: {fileID: 5374880666536229423} + m_Layer: 5 + m_Name: LegendsX + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2581675890115619580 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4375453557142464801} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1750250400045347475} + - {fileID: 8473536528693599174} + m_Father: {fileID: 842792608162333385} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 5, y: -5} + m_SizeDelta: {x: 10, y: 20} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &5374880666536229423 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4375453557142464801} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_Spacing: 0 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &4917723141099053105 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3363869356760374277} + - component: {fileID: 4476095696555559496} + - component: {fileID: 5567867155054281268} + m_Layer: 5 + m_Name: Backdrop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3363869356760374277 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2138752905301465689} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4476095696555559496 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_CullTransparentMesh: 1 +--- !u!114 &5567867155054281268 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.22745098} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5274949478677654638 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5885248672530866080} + m_Layer: 5 + m_Name: Legend0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5885248672530866080 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5274949478677654638} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5455569689841791731} + - {fileID: 5732919540871248940} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &5352407663590911692 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9183933987449881395} + - component: {fileID: 7256530256701424070} + - component: {fileID: 4330748233085529081} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9183933987449881395 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5389867435348264296} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &7256530256701424070 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_CullTransparentMesh: 1 +--- !u!114 &4330748233085529081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &5693887164122654533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6309157798075429021} + m_Layer: 5 + m_Name: Legend75 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6309157798075429021 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5693887164122654533} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7988638580994470440} + - {fileID: 3076841666317101811} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.75} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &5810998373083543261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5071673759804795070} + - component: {fileID: 1370951599340238612} + - component: {fileID: 2160324143502055429} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5071673759804795070 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 842792608162333385} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &1370951599340238612 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_CullTransparentMesh: 1 +--- !u!114 &2160324143502055429 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: BANDWIDTH +--- !u!1 &6326536691934325288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6145669649686337282} + - component: {fileID: 968747920458182069} + - component: {fileID: 4680362740251307526} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6145669649686337282 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8455135462272940247} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &968747920458182069 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_CullTransparentMesh: 1 +--- !u!114 &4680362740251307526 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6354099053443266201 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3127105718844619361} + - component: {fileID: 6920956740542454426} + - component: {fileID: 2248143582364066648} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3127105718844619361 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8455135462272940247} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6920956740542454426 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_CullTransparentMesh: 1 +--- !u!114 &2248143582364066648 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &6498744302665369373 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2927000160895229417} + - component: {fileID: 3795603901461861956} + - component: {fileID: 3504239642613663755} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2927000160895229417 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8473536528693599174} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3795603901461861956 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_CullTransparentMesh: 1 +--- !u!114 &3504239642613663755 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: out +--- !u!1 &6501576574154348994 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8455135462272940247} + m_Layer: 5 + m_Name: Legend50 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8455135462272940247 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6501576574154348994} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6145669649686337282} + - {fileID: 3127105718844619361} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6868069573715158019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5389867435348264296} + m_Layer: 5 + m_Name: Legend25 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5389867435348264296 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6868069573715158019} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8254041970903625228} + - {fileID: 9183933987449881395} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.25} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &7002258827437049681 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5157207313487273501} + - component: {fileID: 5222763877749258818} + - component: {fileID: 1845491664005460411} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5157207313487273501 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1750250400045347475} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5222763877749258818 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_CullTransparentMesh: 1 +--- !u!114 &1845491664005460411 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &7189887428595669623 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7988638580994470440} + - component: {fileID: 7267528306069058291} + - component: {fileID: 4777559063183442036} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7988638580994470440 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6309157798075429021} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7267528306069058291 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_CullTransparentMesh: 1 +--- !u!114 &4777559063183442036 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &7203666293600016388 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3683314132040949185} + - component: {fileID: 263296843630000285} + - component: {fileID: 5681678021283145729} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3683314132040949185 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1750250400045347475} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &263296843630000285 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_CullTransparentMesh: 1 +--- !u!114 &5681678021283145729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: in +--- !u!1 &8334833703202091165 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8254041970903625228} + - component: {fileID: 9068658072675687366} + - component: {fileID: 3509666831540494135} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8254041970903625228 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5389867435348264296} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &9068658072675687366 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_CullTransparentMesh: 1 +--- !u!114 &3509666831540494135 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &8757401605356351412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3076841666317101811} + - component: {fileID: 3104114958221384706} + - component: {fileID: 97403263534861610} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3076841666317101811 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6309157798075429021} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &3104114958221384706 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_CullTransparentMesh: 1 +--- !u!114 &97403263534861610 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab.meta b/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab.meta new file mode 100644 index 0000000..440e669 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 3c7a97355c25a2b4da731b53876f8a8b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/Prefabs/BandwidthGraph.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab b/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab new file mode 100644 index 0000000..b29376f --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab @@ -0,0 +1,1976 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &24878003039380082 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1738718049027005141} + m_Layer: 5 + m_Name: Container + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1738718049027005141 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 24878003039380082} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546206307382570} + - {fileID: 343546206776216637} + - {fileID: 343546206294766220} + - {fileID: 343546206649983697} + m_Father: {fileID: 343546206339761112} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 15, y: 0} + m_SizeDelta: {x: -50, y: -60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546204850636262 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546204850636257} + - component: {fileID: 343546204850636259} + - component: {fileID: 343546204850636256} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546204850636257 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204850636262} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546206877774020} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &343546204850636259 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204850636262} + m_CullTransparentMesh: 1 +--- !u!114 &343546204850636256 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204850636262} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &343546204890306331 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546204890306330} + - component: {fileID: 343546204890306340} + - component: {fileID: 343546204890306341} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546204890306330 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204890306331} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546206506823101} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546204890306340 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204890306331} + m_CullTransparentMesh: 1 +--- !u!114 &343546204890306341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546204890306331} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: max +--- !u!1 &343546205136049349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205136049348} + - component: {fileID: 343546205136049350} + - component: {fileID: 343546205136049351} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205136049348 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205136049349} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205806955365} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &343546205136049350 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205136049349} + m_CullTransparentMesh: 1 +--- !u!114 &343546205136049351 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205136049349} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &343546205212282750 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205212282745} + - component: {fileID: 343546205212282747} + m_Layer: 5 + m_Name: LegendAVG + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205212282745 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205212282750} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205253700114} + - {fileID: 343546206801970585} + m_Father: {fileID: 343546206294766220} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205212282747 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205212282750} + m_CullTransparentMesh: 1 +--- !u!1 &343546205253700115 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205253700114} + - component: {fileID: 343546205253700124} + - component: {fileID: 343546205253700125} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205253700114 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205253700115} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205212282745} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205253700124 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205253700115} + m_CullTransparentMesh: 1 +--- !u!114 &343546205253700125 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205253700115} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546205281663119 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205281663118} + - component: {fileID: 343546205281663113} + m_Layer: 5 + m_Name: LegendMIN + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205281663118 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205281663119} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205496339525} + - {fileID: 343546206359818246} + m_Father: {fileID: 343546206294766220} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205281663113 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205281663119} + m_CullTransparentMesh: 1 +--- !u!1 &343546205394542240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205394542243} + - component: {fileID: 343546205394542253} + - component: {fileID: 343546205394542242} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205394542243 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205394542240} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205508279401} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &343546205394542253 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205394542240} + m_CullTransparentMesh: 1 +--- !u!114 &343546205394542242 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205394542240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &343546205496339642 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205496339525} + - component: {fileID: 343546205496339527} + - component: {fileID: 343546205496339524} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205496339525 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205496339642} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205281663118} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205496339527 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205496339642} + m_CullTransparentMesh: 1 +--- !u!114 &343546205496339524 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205496339642} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546205500504725 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205500504724} + - component: {fileID: 343546205500504726} + - component: {fileID: 343546205500504727} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205500504724 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205500504725} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546206877774020} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205500504726 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205500504725} + m_CullTransparentMesh: 1 +--- !u!114 &343546205500504727 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205500504725} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546205508279406 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205508279401} + m_Layer: 5 + m_Name: Legend0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205508279401 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205508279406} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546206740227476} + - {fileID: 343546205394542243} + m_Father: {fileID: 343546206776216637} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546205523578647 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205523578646} + - component: {fileID: 343546205523578640} + - component: {fileID: 343546205523578641} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205523578646 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205523578647} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205634725308} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205523578640 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205523578647} + m_CullTransparentMesh: 1 +--- !u!114 &343546205523578641 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205523578647} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546205634725309 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205634725308} + m_Layer: 5 + m_Name: Legend50 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205634725308 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205634725309} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205523578646} + - {fileID: 343546206440079829} + m_Father: {fileID: 343546206776216637} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546205685920600 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205685920603} + m_Layer: 5 + m_Name: Legend75 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205685920603 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205685920600} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546206488145202} + - {fileID: 343546206326199842} + m_Father: {fileID: 343546206776216637} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.75} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546205806955354 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205806955365} + m_Layer: 5 + m_Name: Legend100 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205806955365 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205806955354} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546206737158417} + - {fileID: 343546205136049348} + m_Father: {fileID: 343546206776216637} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546205859589119 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546205859589118} + - component: {fileID: 343546205859589112} + - component: {fileID: 343546205859589113} + m_Layer: 5 + m_Name: Backdrop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546205859589118 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205859589119} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546206339761112} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546205859589112 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205859589119} + m_CullTransparentMesh: 1 +--- !u!114 &343546205859589113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546205859589119} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.22745098} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206294766221 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206294766220} + - component: {fileID: 343546206294766223} + m_Layer: 5 + m_Name: LegendsX + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206294766220 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206294766221} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205212282745} + - {fileID: 343546205281663118} + - {fileID: 343546206506823101} + m_Father: {fileID: 1738718049027005141} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 5, y: -5} + m_SizeDelta: {x: 10, y: 20} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &343546206294766223 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206294766221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_Spacing: 0 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &343546206307382571 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206307382570} + - component: {fileID: 343546206307382580} + - component: {fileID: 343546206307382581} + m_Layer: 5 + m_Name: GraphContent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206307382570 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206307382571} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1738718049027005141} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206307382580 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206307382571} + m_CullTransparentMesh: 1 +--- !u!114 &343546206307382581 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206307382571} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206326199843 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206326199842} + - component: {fileID: 343546206326199852} + - component: {fileID: 343546206326199853} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206326199842 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206326199843} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205685920603} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &343546206326199852 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206326199843} + m_CullTransparentMesh: 1 +--- !u!114 &343546206326199853 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206326199843} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &343546206339761113 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206339761112} + - component: {fileID: 4901013733809370033} + m_Layer: 5 + m_Name: FPSMinMaxAvg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206339761112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206339761113} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205859589118} + - {fileID: 1738718049027005141} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &4901013733809370033 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206339761113} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73bc3b929ec94537a8dbd67eb9d0c2c6, type: 3} + m_Name: + m_EditorClassIdentifier: + Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + Renderer: {fileID: 343546206307382581} + Points: 16 + SecondsPerPoint: 0.5 + CategoryColors: + - {r: 0, g: 1, b: 1, a: 1} + - {r: 1, g: 0, b: 0, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + IsStacked: 0 + LegendTexts: + - {fileID: 343546205394542242} + - {fileID: 343546204850636256} + - {fileID: 343546206440079828} + - {fileID: 343546206326199853} + - {fileID: 343546205136049351} + runtimeMaterial: {fileID: 0} +--- !u!1 &343546206359818247 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206359818246} + - component: {fileID: 343546206359818240} + - component: {fileID: 343546206359818241} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206359818246 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206359818247} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205281663118} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206359818240 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206359818247} + m_CullTransparentMesh: 1 +--- !u!114 &343546206359818241 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206359818247} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: min +--- !u!1 &343546206440079818 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206440079829} + - component: {fileID: 343546206440079831} + - component: {fileID: 343546206440079828} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206440079829 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206440079818} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205634725308} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &343546206440079831 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206440079818} + m_CullTransparentMesh: 1 +--- !u!114 &343546206440079828 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206440079818} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &343546206488145203 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206488145202} + - component: {fileID: 343546206488145212} + - component: {fileID: 343546206488145213} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206488145202 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206488145203} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205685920603} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206488145212 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206488145203} + m_CullTransparentMesh: 1 +--- !u!114 &343546206488145213 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206488145203} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206506823090 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206506823101} + - component: {fileID: 343546206506823100} + m_Layer: 5 + m_Name: LegendMAX + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206506823101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206506823090} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546206516923994} + - {fileID: 343546204890306330} + m_Father: {fileID: 343546206294766220} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206506823100 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206506823090} + m_CullTransparentMesh: 1 +--- !u!1 &343546206516923995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206516923994} + - component: {fileID: 343546206516924004} + - component: {fileID: 343546206516924005} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206516923994 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206516923995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546206506823101} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206516924004 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206516923995} + m_CullTransparentMesh: 1 +--- !u!114 &343546206516924005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206516923995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206649983702 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206649983697} + - component: {fileID: 343546206649983699} + - component: {fileID: 343546206649983696} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206649983697 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206649983702} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1738718049027005141} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &343546206649983699 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206649983702} + m_CullTransparentMesh: 1 +--- !u!114 &343546206649983696 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206649983702} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: FPS +--- !u!1 &343546206737158422 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206737158417} + - component: {fileID: 343546206737158419} + - component: {fileID: 343546206737158416} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206737158417 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206737158422} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205806955365} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206737158419 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206737158422} + m_CullTransparentMesh: 1 +--- !u!114 &343546206737158416 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206737158422} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206740227477 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206740227476} + - component: {fileID: 343546206740227478} + - component: {fileID: 343546206740227479} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206740227476 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206740227477} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205508279401} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206740227478 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206740227477} + m_CullTransparentMesh: 1 +--- !u!114 &343546206740227479 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206740227477} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &343546206776216626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206776216637} + m_Layer: 5 + m_Name: LegendsY + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206776216637 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206776216626} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205508279401} + - {fileID: 343546206877774020} + - {fileID: 343546205634725308} + - {fileID: 343546205685920603} + - {fileID: 343546205806955365} + m_Father: {fileID: 1738718049027005141} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &343546206801970590 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206801970585} + - component: {fileID: 343546206801970587} + - component: {fileID: 343546206801970584} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206801970585 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206801970590} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 343546205212282745} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &343546206801970587 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206801970590} + m_CullTransparentMesh: 1 +--- !u!114 &343546206801970584 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206801970590} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: avg +--- !u!1 &343546206877774021 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 343546206877774020} + m_Layer: 5 + m_Name: Legend25 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &343546206877774020 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 343546206877774021} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 343546205500504724} + - {fileID: 343546204850636257} + m_Father: {fileID: 343546206776216637} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.25} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab.meta b/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab.meta new file mode 100644 index 0000000..4e2d104 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9bdc42bca9b7109428d00fe33bdb5102 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/Prefabs/FPSMinMaxAvg.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab b/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab new file mode 100644 index 0000000..b90a863 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab @@ -0,0 +1,765 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2777084101886578567 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3864348419064627986} + - component: {fileID: 4699359553083341963} + m_Layer: 5 + m_Name: Graphs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &3864348419064627986 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2777084101886578567} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4509006437822490170} + - {fileID: 522813179161291686} + - {fileID: 7802229218722708586} + m_Father: {fileID: 5551289487596275721} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &4699359553083341963 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2777084101886578567} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 10 + m_Right: 0 + m_Top: 10 + m_Bottom: 0 + m_ChildAlignment: 2 + m_Spacing: 0 + m_ChildForceExpandWidth: 0 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &4512081604627528395 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5551289487596275721} + - component: {fileID: 5641452096830013034} + - component: {fileID: 4961392508020504993} + - component: {fileID: 1349218098020237989} + - component: {fileID: 8415974033864006777} + m_Layer: 5 + m_Name: GraphCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5551289487596275721 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4512081604627528395} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 3864348419064627986} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &5641452096830013034 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4512081604627528395} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &4961392508020504993 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4512081604627528395} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1280, y: 720} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 1 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &1349218098020237989 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4512081604627528395} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &8415974033864006777 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4512081604627528395} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a27b133d890c41828d3b01ffa12fe440, type: 3} + m_Name: + m_EditorClassIdentifier: + Key: 291 + ToToggle: {fileID: 2777084101886578567} +--- !u!1001 &4204022305993221602 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 3864348419064627986} + m_Modifications: + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.x + value: 86.666664 + objectReference: {fileID: 0} + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 43.333332 + objectReference: {fileID: 0} + - target: {fileID: 343546205212282745, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.x + value: 86.666664 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 130 + objectReference: {fileID: 0} + - target: {fileID: 343546205281663118, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.x + value: 300 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.y + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 1668.6208 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -85 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 343546206339761113, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_Name + value: FPSMinMaxAvg + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.x + value: 86.666664 + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 216.66666 + objectReference: {fileID: 0} + - target: {fileID: 343546206506823101, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 9bdc42bca9b7109428d00fe33bdb5102, type: 3} +--- !u!224 &4509006437822490170 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 343546206339761112, guid: 9bdc42bca9b7109428d00fe33bdb5102, + type: 3} + m_PrefabInstance: {fileID: 4204022305993221602} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7469102913200609509 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 3864348419064627986} + m_Modifications: + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.x + value: 130 + objectReference: {fileID: 0} + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 195 + objectReference: {fileID: 0} + - target: {fileID: 942441613928011978, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 2997867828362567431, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_Name + value: PingGraph + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.x + value: 130 + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 65 + objectReference: {fileID: 0} + - target: {fileID: 6899184289734897349, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.x + value: 300 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_SizeDelta.y + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 1968.6208 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -85 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ed3b4e27086dcc64b8c6605011a321e2, type: 3} +--- !u!224 &522813179161291686 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 6982534731248530243, guid: ed3b4e27086dcc64b8c6605011a321e2, + type: 3} + m_PrefabInstance: {fileID: 7469102913200609509} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &8208221870570858035 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 3864348419064627986} + m_Modifications: + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.x + value: 130 + objectReference: {fileID: 0} + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 65 + objectReference: {fileID: 0} + - target: {fileID: 1750250400045347475, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 1986485545668258777, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: Points + value: 32 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.x + value: 300 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.y + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 2268.6208 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -85 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3670180597793129839, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_Name + value: NetworkGraph + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchorMin.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.x + value: 130 + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_SizeDelta.y + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 195 + objectReference: {fileID: 0} + - target: {fileID: 8473536528693599174, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: -10 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 3c7a97355c25a2b4da731b53876f8a8b, type: 3} +--- !u!224 &7802229218722708586 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 2138752905301465689, guid: 3c7a97355c25a2b4da731b53876f8a8b, + type: 3} + m_PrefabInstance: {fileID: 8208221870570858035} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab.meta b/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab.meta new file mode 100644 index 0000000..4e4dab5 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e87e1847def3c1f41b19b7df4f0920b3 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/Prefabs/GraphCanvas.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab b/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab new file mode 100644 index 0000000..bb77911 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab @@ -0,0 +1,2888 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &119935549420283780 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8824290184142807954} + m_Layer: 5 + m_Name: Legend100 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8824290184142807954 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 119935549420283780} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8397968435809926716} + - {fileID: 8383045724353990353} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &215824790723025810 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8473536528693599174} + - component: {fileID: 8359308210431883230} + m_Layer: 5 + m_Name: LegendOUT + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8473536528693599174 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 215824790723025810} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5970650343794535896} + - {fileID: 2927000160895229417} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8359308210431883230 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 215824790723025810} + m_CullTransparentMesh: 1 +--- !u!1 &230788547622420441 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 968396119680197966} + - component: {fileID: 5129519199212594243} + - component: {fileID: 5123833194418803548} + m_Layer: 5 + m_Name: GraphContent - Bandwidth + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &968396119680197966 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 842792608162333385} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -10.1066, y: 0} + m_SizeDelta: {x: -60.2131, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5129519199212594243 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_CullTransparentMesh: 1 +--- !u!114 &5123833194418803548 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 230788547622420441} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &969091221012082297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8397968435809926716} + - component: {fileID: 5852067364008015930} + - component: {fileID: 4136376136871219296} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8397968435809926716 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8824290184142807954} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5852067364008015930 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_CullTransparentMesh: 1 +--- !u!114 &4136376136871219296 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 969091221012082297} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1144042303701158085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2770498519712146759} + - component: {fileID: 1909324844259712510} + - component: {fileID: 6801190371405574669} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2770498519712146759 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1144042303701158085} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6118054815374899758} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1909324844259712510 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1144042303701158085} + m_CullTransparentMesh: 1 +--- !u!114 &6801190371405574669 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1144042303701158085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: jitter +--- !u!1 &1194010084318017500 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3962977762644453858} + m_Layer: 5 + m_Name: LegendsY - Ping + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3962977762644453858 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1194010084318017500} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8467240887132563218} + - {fileID: 2900620391526308637} + - {fileID: 1423636040061542291} + - {fileID: 3701477534332925528} + - {fileID: 5515203252368553261} + m_Father: {fileID: 842792608162333385} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 109.89, y: 0} + m_SizeDelta: {x: -199.79, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1649716185402538073 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7375623566472823448} + - component: {fileID: 7280101622563951250} + - component: {fileID: 1772663036056914474} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7375623566472823448 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1649716185402538073} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6118054815374899758} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7280101622563951250 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1649716185402538073} + m_CullTransparentMesh: 1 +--- !u!114 &1772663036056914474 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1649716185402538073} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1694800138959048866 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5970650343794535896} + - component: {fileID: 3299375740833370906} + - component: {fileID: 6202027950733238712} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5970650343794535896 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8473536528693599174} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3299375740833370906 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_CullTransparentMesh: 1 +--- !u!114 &6202027950733238712 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1694800138959048866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1711370235648153955 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5455569689841791731} + - component: {fileID: 8443939090520853786} + - component: {fileID: 1177453892628721408} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5455569689841791731 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5885248672530866080} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8443939090520853786 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_CullTransparentMesh: 1 +--- !u!114 &1177453892628721408 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1711370235648153955} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2002525035342291879 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1750250400045347475} + - component: {fileID: 8835486359842310823} + m_Layer: 5 + m_Name: LegendIN + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1750250400045347475 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002525035342291879} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5157207313487273501} + - {fileID: 3683314132040949185} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8835486359842310823 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002525035342291879} + m_CullTransparentMesh: 1 +--- !u!1 &3357588547163078786 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2288491264626255212} + m_Layer: 5 + m_Name: LegendsY - Bandwidth + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2288491264626255212 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3357588547163078786} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5885248672530866080} + - {fileID: 5389867435348264296} + - {fileID: 8455135462272940247} + - {fileID: 6309157798075429021} + - {fileID: 8824290184142807954} + m_Father: {fileID: 842792608162333385} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -10.107, y: 0} + m_SizeDelta: {x: -60.213, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &3534129496521135982 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 842792608162333385} + m_Layer: 5 + m_Name: Container + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &842792608162333385 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3534129496521135982} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 968396119680197966} + - {fileID: 5267541382525022770} + - {fileID: 2288491264626255212} + - {fileID: 3962977762644453858} + - {fileID: 2581675890115619580} + - {fileID: 5071673759804795070} + m_Father: {fileID: 2138752905301465689} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 15, y: 0} + m_SizeDelta: {x: -50, y: -60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &3569519790910280589 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1259420167673541393} + - component: {fileID: 4579425422591491119} + - component: {fileID: 8580294978504068442} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1259420167673541393 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3569519790910280589} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1423636040061542291} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -45, y: 0} + m_SizeDelta: {x: 40, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &4579425422591491119 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3569519790910280589} + m_CullTransparentMesh: 1 +--- !u!114 &8580294978504068442 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3569519790910280589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &3670180597793129839 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2138752905301465689} + - component: {fileID: 8024388048541391361} + - component: {fileID: 6891156770396053448} + m_Layer: 5 + m_Name: NetworkGraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2138752905301465689 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3670180597793129839} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3363869356760374277} + - {fileID: 842792608162333385} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &8024388048541391361 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3670180597793129839} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e1ae19b97f0e4a5eb8cf5158d97506f5, type: 3} + m_Name: + m_EditorClassIdentifier: + Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + Renderer: {fileID: 5123833194418803548} + Points: 64 + SecondsPerPoint: 0.5 + CategoryColors: + - {r: 1, g: 0, b: 0, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + IsStacked: 0 + LegendTexts: + - {fileID: 142216866270345907} + - {fileID: 4330748233085529081} + - {fileID: 2248143582364066648} + - {fileID: 97403263534861610} + - {fileID: 4349487955187298716} + runtimeMaterial: {fileID: 0} +--- !u!114 &6891156770396053448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3670180597793129839} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 14a68afedbbf4568b0decc5c3fe6dfd9, type: 3} + m_Name: + m_EditorClassIdentifier: + Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + Renderer: {fileID: 3880664398471042142} + Points: 64 + SecondsPerPoint: 0.5 + CategoryColors: + - {r: 0, g: 1, b: 1, a: 1} + - {r: 1, g: 0.92156863, b: 0.015686275, a: 1} + IsStacked: 0 + LegendTexts: + - {fileID: 2117081375211614847} + - {fileID: 7864316414649457688} + - {fileID: 8580294978504068442} + - {fileID: 1639235332378233126} + - {fileID: 7668278254153150358} + runtimeMaterial: {fileID: 0} +--- !u!1 &3678091663373353095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5732919540871248940} + - component: {fileID: 6719434420897279190} + - component: {fileID: 142216866270345907} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5732919540871248940 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5885248672530866080} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6719434420897279190 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_CullTransparentMesh: 1 +--- !u!114 &142216866270345907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3678091663373353095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &3714570775115803475 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8383045724353990353} + - component: {fileID: 1355767179239727018} + - component: {fileID: 4349487955187298716} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8383045724353990353 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8824290184142807954} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &1355767179239727018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_CullTransparentMesh: 1 +--- !u!114 &4349487955187298716 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3714570775115803475} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &4375453557142464801 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2581675890115619580} + - component: {fileID: 5374880666536229423} + m_Layer: 5 + m_Name: LegendsX + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2581675890115619580 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4375453557142464801} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1750250400045347475} + - {fileID: 8473536528693599174} + - {fileID: 4635932635135080026} + - {fileID: 6118054815374899758} + m_Father: {fileID: 842792608162333385} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 5, y: -5} + m_SizeDelta: {x: 10, y: 20} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &5374880666536229423 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4375453557142464801} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_Spacing: 0 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &4490397563866728061 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8036502514150168521} + - component: {fileID: 3374747859601888581} + - component: {fileID: 460765458322436772} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8036502514150168521 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4490397563866728061} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4635932635135080026} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3374747859601888581 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4490397563866728061} + m_CullTransparentMesh: 1 +--- !u!114 &460765458322436772 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4490397563866728061} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &4492650180689071546 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7595841946320721050} + - component: {fileID: 186511036850520057} + - component: {fileID: 7292537739385968087} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7595841946320721050 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4492650180689071546} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4635932635135080026} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &186511036850520057 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4492650180689071546} + m_CullTransparentMesh: 1 +--- !u!114 &7292537739385968087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4492650180689071546} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: ping +--- !u!1 &4671836082000350783 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1224777268200255961} + - component: {fileID: 6711771988030203581} + - component: {fileID: 7864316414649457688} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1224777268200255961 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4671836082000350783} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2900620391526308637} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -45, y: 0} + m_SizeDelta: {x: 40, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6711771988030203581 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4671836082000350783} + m_CullTransparentMesh: 1 +--- !u!114 &7864316414649457688 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4671836082000350783} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &4723476562664894706 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3701477534332925528} + m_Layer: 5 + m_Name: Legend75 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3701477534332925528 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4723476562664894706} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6198365725618080772} + m_Father: {fileID: 3962977762644453858} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.75} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4917723141099053105 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3363869356760374277} + - component: {fileID: 4476095696555559496} + - component: {fileID: 5567867155054281268} + m_Layer: 5 + m_Name: Backdrop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3363869356760374277 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2138752905301465689} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4476095696555559496 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_CullTransparentMesh: 1 +--- !u!114 &5567867155054281268 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4917723141099053105} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.22745098} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5075371807985313428 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4635932635135080026} + - component: {fileID: 7147312742844013158} + m_Layer: 5 + m_Name: LegendPING + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4635932635135080026 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075371807985313428} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8036502514150168521} + - {fileID: 7595841946320721050} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7147312742844013158 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075371807985313428} + m_CullTransparentMesh: 1 +--- !u!1 &5274949478677654638 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5885248672530866080} + m_Layer: 5 + m_Name: Legend0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5885248672530866080 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5274949478677654638} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5455569689841791731} + - {fileID: 5732919540871248940} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &5352407663590911692 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9183933987449881395} + - component: {fileID: 7256530256701424070} + - component: {fileID: 4330748233085529081} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9183933987449881395 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5389867435348264296} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &7256530256701424070 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_CullTransparentMesh: 1 +--- !u!114 &4330748233085529081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5352407663590911692} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &5597103007742484545 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1423636040061542291} + m_Layer: 5 + m_Name: Legend50 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1423636040061542291 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5597103007742484545} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1259420167673541393} + m_Father: {fileID: 3962977762644453858} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &5628951584669016692 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5267541382525022770} + - component: {fileID: 3449685404681157396} + - component: {fileID: 3880664398471042142} + m_Layer: 5 + m_Name: GraphContent - Ping + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5267541382525022770 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5628951584669016692} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 842792608162333385} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -10.1066, y: 0} + m_SizeDelta: {x: -60.2131, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3449685404681157396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5628951584669016692} + m_CullTransparentMesh: 1 +--- !u!114 &3880664398471042142 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5628951584669016692} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5693887164122654533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6309157798075429021} + m_Layer: 5 + m_Name: Legend75 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6309157798075429021 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5693887164122654533} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7988638580994470440} + - {fileID: 3076841666317101811} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.75} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &5810998373083543261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5071673759804795070} + - component: {fileID: 1370951599340238612} + - component: {fileID: 2160324143502055429} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5071673759804795070 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 842792608162333385} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &1370951599340238612 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_CullTransparentMesh: 1 +--- !u!114 &2160324143502055429 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5810998373083543261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: netgraph +--- !u!1 &5949791456184720458 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 808931863454774844} + - component: {fileID: 3262084368540049565} + - component: {fileID: 7668278254153150358} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &808931863454774844 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5949791456184720458} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5515203252368553261} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -45, y: 0} + m_SizeDelta: {x: 40, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &3262084368540049565 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5949791456184720458} + m_CullTransparentMesh: 1 +--- !u!114 &7668278254153150358 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5949791456184720458} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &6299708506135008504 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6198365725618080772} + - component: {fileID: 4666306959683799360} + - component: {fileID: 1639235332378233126} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6198365725618080772 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6299708506135008504} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3701477534332925528} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -45, y: 0} + m_SizeDelta: {x: 40, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &4666306959683799360 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6299708506135008504} + m_CullTransparentMesh: 1 +--- !u!114 &1639235332378233126 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6299708506135008504} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &6326536691934325288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6145669649686337282} + - component: {fileID: 968747920458182069} + - component: {fileID: 4680362740251307526} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6145669649686337282 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8455135462272940247} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &968747920458182069 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_CullTransparentMesh: 1 +--- !u!114 &4680362740251307526 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6326536691934325288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6354099053443266201 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3127105718844619361} + - component: {fileID: 6920956740542454426} + - component: {fileID: 2248143582364066648} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3127105718844619361 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8455135462272940247} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6920956740542454426 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_CullTransparentMesh: 1 +--- !u!114 &2248143582364066648 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6354099053443266201} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &6473252433622726265 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5515203252368553261} + m_Layer: 5 + m_Name: Legend100 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5515203252368553261 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6473252433622726265} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 808931863454774844} + m_Father: {fileID: 3962977762644453858} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6498744302665369373 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2927000160895229417} + - component: {fileID: 3795603901461861956} + - component: {fileID: 3504239642613663755} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2927000160895229417 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8473536528693599174} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3795603901461861956 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_CullTransparentMesh: 1 +--- !u!114 &3504239642613663755 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6498744302665369373} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: out +--- !u!1 &6501576574154348994 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8455135462272940247} + m_Layer: 5 + m_Name: Legend50 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8455135462272940247 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6501576574154348994} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6145669649686337282} + - {fileID: 3127105718844619361} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6697282991844538288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8467240887132563218} + m_Layer: 5 + m_Name: Legend0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8467240887132563218 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6697282991844538288} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8045971123728951344} + m_Father: {fileID: 3962977762644453858} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6868069573715158019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5389867435348264296} + m_Layer: 5 + m_Name: Legend25 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5389867435348264296 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6868069573715158019} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8254041970903625228} + - {fileID: 9183933987449881395} + m_Father: {fileID: 2288491264626255212} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.25} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &7002258827437049681 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5157207313487273501} + - component: {fileID: 5222763877749258818} + - component: {fileID: 1845491664005460411} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5157207313487273501 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1750250400045347475} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5222763877749258818 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_CullTransparentMesh: 1 +--- !u!114 &1845491664005460411 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7002258827437049681} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &7189887428595669623 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7988638580994470440} + - component: {fileID: 7267528306069058291} + - component: {fileID: 4777559063183442036} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7988638580994470440 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6309157798075429021} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7267528306069058291 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_CullTransparentMesh: 1 +--- !u!114 &4777559063183442036 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7189887428595669623} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &7203666293600016388 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3683314132040949185} + - component: {fileID: 263296843630000285} + - component: {fileID: 5681678021283145729} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3683314132040949185 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1750250400045347475} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &263296843630000285 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_CullTransparentMesh: 1 +--- !u!114 &5681678021283145729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7203666293600016388} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: in +--- !u!1 &8077720310600692407 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6118054815374899758} + - component: {fileID: 3202099948270756252} + m_Layer: 5 + m_Name: LegendJITTER + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6118054815374899758 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8077720310600692407} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7375623566472823448} + - {fileID: 2770498519712146759} + m_Father: {fileID: 2581675890115619580} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3202099948270756252 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8077720310600692407} + m_CullTransparentMesh: 1 +--- !u!1 &8334833703202091165 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8254041970903625228} + - component: {fileID: 9068658072675687366} + - component: {fileID: 3509666831540494135} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8254041970903625228 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5389867435348264296} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &9068658072675687366 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_CullTransparentMesh: 1 +--- !u!114 &3509666831540494135 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8334833703202091165} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &8757401605356351412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3076841666317101811} + - component: {fileID: 3104114958221384706} + - component: {fileID: 97403263534861610} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3076841666317101811 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6309157798075429021} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &3104114958221384706 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_CullTransparentMesh: 1 +--- !u!114 &97403263534861610 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8757401605356351412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &8983883851149759884 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8045971123728951344} + - component: {fileID: 1946944942956829893} + - component: {fileID: 2117081375211614847} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8045971123728951344 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8983883851149759884} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8467240887132563218} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -45, y: 0} + m_SizeDelta: {x: 40, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &1946944942956829893 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8983883851149759884} + m_CullTransparentMesh: 1 +--- !u!114 &2117081375211614847 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8983883851149759884} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &9092185120150146117 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2900620391526308637} + m_Layer: 5 + m_Name: Legend25 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2900620391526308637 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9092185120150146117} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1224777268200255961} + m_Father: {fileID: 3962977762644453858} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.25} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab.meta b/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab.meta new file mode 100644 index 0000000..1e2c86c --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a4ee3092d7c7f4a38a70b11014175ebd +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/Prefabs/NetworkGraph.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab b/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab new file mode 100644 index 0000000..c35ae4d --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab @@ -0,0 +1,1776 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &512166646911724149 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5569695547238921462} + - component: {fileID: 7180649172285861411} + - component: {fileID: 3698306165924257989} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5569695547238921462 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512166646911724149} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4620809971601425299} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7180649172285861411 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512166646911724149} + m_CullTransparentMesh: 1 +--- !u!114 &3698306165924257989 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 512166646911724149} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &693974290553253915 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2454008239292490697} + - component: {fileID: 6928098193469425262} + - component: {fileID: 9151821596118048258} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2454008239292490697 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 693974290553253915} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7987015295734336241} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6928098193469425262 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 693974290553253915} + m_CullTransparentMesh: 1 +--- !u!114 &9151821596118048258 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 693974290553253915} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &724734797682004671 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 216369457880424682} + - component: {fileID: 6446260028879253612} + m_Layer: 5 + m_Name: LegendsX + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &216369457880424682 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724734797682004671} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6899184289734897349} + - {fileID: 942441613928011978} + m_Father: {fileID: 5294687292649652416} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 5, y: -5} + m_SizeDelta: {x: 10, y: 20} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &6446260028879253612 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 724734797682004671} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_Spacing: 0 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &1093758345687749999 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7987015295734336241} + m_Layer: 5 + m_Name: Legend25 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7987015295734336241 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1093758345687749999} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 911697406546784338} + - {fileID: 2454008239292490697} + m_Father: {fileID: 1469817193488350550} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.25} + m_AnchorMax: {x: 1, y: 0.25} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1549744656742816016 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5294687292649652416} + m_Layer: 5 + m_Name: Container + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5294687292649652416 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1549744656742816016} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1768608949435380201} + - {fileID: 1469817193488350550} + - {fileID: 216369457880424682} + - {fileID: 6975151376875653975} + m_Father: {fileID: 6982534731248530243} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 15, y: 0} + m_SizeDelta: {x: -50, y: -60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1723664113960925886 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6658247662285819325} + - component: {fileID: 1965012378351765188} + - component: {fileID: 4336023028329030949} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6658247662285819325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1723664113960925886} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7590176880698012387} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1965012378351765188 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1723664113960925886} + m_CullTransparentMesh: 1 +--- !u!114 &4336023028329030949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1723664113960925886} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1751972084552208902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7870100887797750244} + m_Layer: 5 + m_Name: Legend50 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7870100887797750244 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1751972084552208902} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7889663160516621925} + - {fileID: 3705598884744263366} + m_Father: {fileID: 1469817193488350550} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1934697115913144479 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2203074428927526136} + - component: {fileID: 2023856609668669680} + - component: {fileID: 2206720168024543330} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2203074428927526136 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1934697115913144479} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 942441613928011978} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2023856609668669680 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1934697115913144479} + m_CullTransparentMesh: 1 +--- !u!114 &2206720168024543330 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1934697115913144479} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0.9215687, b: 0.015686275, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2810967667379106609 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1217973610716945855} + - component: {fileID: 1127519584872800040} + - component: {fileID: 362765526694760680} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1217973610716945855 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2810967667379106609} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7590176880698012387} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &1127519584872800040 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2810967667379106609} + m_CullTransparentMesh: 1 +--- !u!114 &362765526694760680 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2810967667379106609} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &2969139731012847270 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6899184289734897349} + - component: {fileID: 5775259578045717352} + m_Layer: 5 + m_Name: LegendPing + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6899184289734897349 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2969139731012847270} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 908890067499602259} + - {fileID: 8083971487120669529} + m_Father: {fileID: 216369457880424682} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5775259578045717352 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2969139731012847270} + m_CullTransparentMesh: 1 +--- !u!1 &2997867828362567431 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6982534731248530243} + - component: {fileID: 5865401507776993270} + m_Layer: 5 + m_Name: PingGraph + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6982534731248530243 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997867828362567431} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1056662130267328870} + - {fileID: 5294687292649652416} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &5865401507776993270 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997867828362567431} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 14a68afedbbf4568b0decc5c3fe6dfd9, type: 3} + m_Name: + m_EditorClassIdentifier: + Material: {fileID: 2100000, guid: 5f77111e39fad6240bbf2a93d735b648, type: 2} + Renderer: {fileID: 5857741690380071345} + Points: 32 + SecondsPerPoint: 0.5 + CategoryColors: + - {r: 0, g: 1, b: 1, a: 1} + - {r: 1, g: 0.92156863, b: 0.015686275, a: 1} + IsStacked: 0 + LegendTexts: + - {fileID: 3160579670834603183} + - {fileID: 9151821596118048258} + - {fileID: 2754244171796987324} + - {fileID: 362765526694760680} + - {fileID: 8382168573226188986} + runtimeMaterial: {fileID: 0} +--- !u!1 &3105901817953974653 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4652558859609211497} + - component: {fileID: 1400924857942257598} + - component: {fileID: 3160579670834603183} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4652558859609211497 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3105901817953974653} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2684192023408130911} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &1400924857942257598 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3105901817953974653} + m_CullTransparentMesh: 1 +--- !u!114 &3160579670834603183 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3105901817953974653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &3205747331435468870 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 942441613928011978} + - component: {fileID: 6327993025711354549} + m_Layer: 5 + m_Name: LegendJitter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &942441613928011978 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3205747331435468870} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2203074428927526136} + - {fileID: 5372474103490645384} + m_Father: {fileID: 216369457880424682} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6327993025711354549 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3205747331435468870} + m_CullTransparentMesh: 1 +--- !u!1 &3640500073563500983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1056662130267328870} + - component: {fileID: 8437258848603187620} + - component: {fileID: 4311061136952486782} + m_Layer: 5 + m_Name: Backdrop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1056662130267328870 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3640500073563500983} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6982534731248530243} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8437258848603187620 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3640500073563500983} + m_CullTransparentMesh: 1 +--- !u!114 &4311061136952486782 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3640500073563500983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.22745098} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &3668972322997488969 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4620809971601425299} + m_Layer: 5 + m_Name: Legend100 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4620809971601425299 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3668972322997488969} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5569695547238921462} + - {fileID: 4579137679805290761} + m_Father: {fileID: 1469817193488350550} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &3867562142981469492 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2684192023408130911} + m_Layer: 5 + m_Name: Legend0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2684192023408130911 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3867562142981469492} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2990412341526050050} + - {fileID: 4652558859609211497} + m_Father: {fileID: 1469817193488350550} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4001027587005364764 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1469817193488350550} + m_Layer: 5 + m_Name: LegendsY + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1469817193488350550 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4001027587005364764} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2684192023408130911} + - {fileID: 7987015295734336241} + - {fileID: 7870100887797750244} + - {fileID: 7590176880698012387} + - {fileID: 4620809971601425299} + m_Father: {fileID: 5294687292649652416} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4037112855574815760 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5372474103490645384} + - component: {fileID: 767451476397572077} + - component: {fileID: 419353126541061517} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5372474103490645384 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4037112855574815760} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 942441613928011978} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &767451476397572077 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4037112855574815760} + m_CullTransparentMesh: 1 +--- !u!114 &419353126541061517 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4037112855574815760} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Jitter +--- !u!1 &5326465489219711421 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7889663160516621925} + - component: {fileID: 8263199366839964538} + - component: {fileID: 4067121774068232129} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7889663160516621925 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5326465489219711421} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7870100887797750244} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8263199366839964538 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5326465489219711421} + m_CullTransparentMesh: 1 +--- !u!114 &4067121774068232129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5326465489219711421} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5506933360427255673 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 911697406546784338} + - component: {fileID: 6011329830179878330} + - component: {fileID: 2951732881719804678} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &911697406546784338 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5506933360427255673} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7987015295734336241} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6011329830179878330 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5506933360427255673} + m_CullTransparentMesh: 1 +--- !u!114 &2951732881719804678 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5506933360427255673} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &5788823770659353615 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1768608949435380201} + - component: {fileID: 8205076076307683200} + - component: {fileID: 5857741690380071345} + m_Layer: 5 + m_Name: GraphContent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1768608949435380201 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5788823770659353615} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5294687292649652416} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8205076076307683200 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5788823770659353615} + m_CullTransparentMesh: 1 +--- !u!114 &5857741690380071345 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5788823770659353615} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6335670163093277870 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2990412341526050050} + - component: {fileID: 8490552629736366217} + - component: {fileID: 7762443815874078549} + m_Layer: 5 + m_Name: Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2990412341526050050 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6335670163093277870} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2684192023408130911} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8490552629736366217 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6335670163093277870} + m_CullTransparentMesh: 1 +--- !u!114 &7762443815874078549 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6335670163093277870} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.40392157} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6425321695431688699 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7590176880698012387} + m_Layer: 5 + m_Name: Legend75 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7590176880698012387 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6425321695431688699} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6658247662285819325} + - {fileID: 1217973610716945855} + m_Father: {fileID: 1469817193488350550} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.75} + m_AnchorMax: {x: 1, y: 0.75} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6673247198283208466 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6975151376875653975} + - component: {fileID: 1474497204505854206} + - component: {fileID: 3859801130584468475} + m_Layer: 5 + m_Name: Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6975151376875653975 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6673247198283208466} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5294687292649652416} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &1474497204505854206 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6673247198283208466} + m_CullTransparentMesh: 1 +--- !u!114 &3859801130584468475 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6673247198283208466} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: PING +--- !u!1 &6858241430425100238 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4579137679805290761} + - component: {fileID: 7750660140099561029} + - component: {fileID: 8382168573226188986} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4579137679805290761 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6858241430425100238} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4620809971601425299} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &7750660140099561029 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6858241430425100238} + m_CullTransparentMesh: 1 +--- !u!114 &8382168573226188986 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6858241430425100238} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &7921722240077587436 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3705598884744263366} + - component: {fileID: 7268291769466718766} + - component: {fileID: 2754244171796987324} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3705598884744263366 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7921722240077587436} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7870100887797750244} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: -1, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -5, y: 50} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &7268291769466718766 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7921722240077587436} + m_CullTransparentMesh: 1 +--- !u!114 &2754244171796987324 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7921722240077587436} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 12 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 10 +--- !u!1 &8434725759024132407 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8083971487120669529} + - component: {fileID: 2625528277965073533} + - component: {fileID: 1427747543481707907} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8083971487120669529 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8434725759024132407} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6899184289734897349} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 4, y: 0} + m_SizeDelta: {x: -8, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2625528277965073533 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8434725759024132407} + m_CullTransparentMesh: 1 +--- !u!114 &1427747543481707907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8434725759024132407} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Ping +--- !u!1 &8835429319627613495 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 908890067499602259} + - component: {fileID: 8735215443978414631} + - component: {fileID: 2493539334624522905} + m_Layer: 5 + m_Name: Color + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &908890067499602259 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8835429319627613495} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6899184289734897349} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8735215443978414631 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8835429319627613495} + m_CullTransparentMesh: 1 +--- !u!114 &2493539334624522905 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8835429319627613495} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 diff --git a/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab.meta b/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab.meta new file mode 100644 index 0000000..57c4881 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ed3b4e27086dcc64b8c6605011a321e2 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/Prefabs/PingGraph.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/StackedGraph.mat b/Assets/Mirror/Components/Profiling/StackedGraph.mat new file mode 100644 index 0000000..a4c4b44 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/StackedGraph.mat @@ -0,0 +1,88 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: StackedGraph + m_Shader: {fileID: 4800000, guid: b5b24284f35f4992bcd4cc43919267d7, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _CategoryCount: 0 + - _ColorMask: 15 + - _Cutoff: 0.5 + - _DataStart: 0 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _MaxValue: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _UVSec: 0 + - _UseUIAlphaClip: 0 + - _Width: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Components/Profiling/StackedGraph.mat.meta b/Assets/Mirror/Components/Profiling/StackedGraph.mat.meta new file mode 100644 index 0000000..6c9422c --- /dev/null +++ b/Assets/Mirror/Components/Profiling/StackedGraph.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 14fba9d19cfe7f346bfb595965558722 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/StackedGraph.mat + uploadId: 736421 diff --git a/Assets/Mirror/Components/Profiling/ToggleHotkey.cs b/Assets/Mirror/Components/Profiling/ToggleHotkey.cs new file mode 100644 index 0000000..130e452 --- /dev/null +++ b/Assets/Mirror/Components/Profiling/ToggleHotkey.cs @@ -0,0 +1,15 @@ +using UnityEngine; +namespace Mirror +{ + public class ToggleHotkey : MonoBehaviour + { + public KeyCode Key = KeyCode.F10; + public GameObject ToToggle; + + void Update() + { + if (Input.GetKeyDown(Key)) + ToToggle.SetActive(!ToToggle.activeSelf); + } + } +} diff --git a/Assets/Mirror/Components/Profiling/ToggleHotkey.cs.meta b/Assets/Mirror/Components/Profiling/ToggleHotkey.cs.meta new file mode 100644 index 0000000..cdcf3aa --- /dev/null +++ b/Assets/Mirror/Components/Profiling/ToggleHotkey.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a27b133d890c41828d3b01ffa12fe440 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/Profiling/ToggleHotkey.cs + uploadId: 736421 diff --git a/Assets/Mirror/Components/RemoteStatistics.cs b/Assets/Mirror/Components/RemoteStatistics.cs new file mode 100644 index 0000000..5b3ede9 --- /dev/null +++ b/Assets/Mirror/Components/RemoteStatistics.cs @@ -0,0 +1,441 @@ +// remote statistics panel from Mirror II to show connections, load, etc. +// server syncs statistics to clients if authenticated. +// +// attach this to a player. +// requires NetworkStatistics component on the Network object. +// +// Unity's OnGUI is the easiest to use solution at the moment. +// * playfab is super complex to set up +// * http servers would be nice, but still need to open ports, live refresh, etc +// +// for safety reasons, let's keep this read-only. +// at least until there's safe authentication. +using System; +using System.IO; +using UnityEngine; + +namespace Mirror +{ + // server -> client + struct Stats + { + // general + public int connections; + public double uptime; + public int configuredTickRate; + public int actualTickRate; + + // traffic + public long sentBytesPerSecond; + public long receiveBytesPerSecond; + + // cpu + public float serverTickInterval; + public double fullUpdateAvg; + public double serverEarlyAvg; + public double serverLateAvg; + public double transportEarlyAvg; + public double transportLateAvg; + + // C# boilerplate + public Stats( + // general + int connections, + double uptime, + int configuredTickRate, + int actualTickRate, + // traffic + long sentBytesPerSecond, + long receiveBytesPerSecond, + // cpu + float serverTickInterval, + double fullUpdateAvg, + double serverEarlyAvg, + double serverLateAvg, + double transportEarlyAvg, + double transportLateAvg + ) + { + // general + this.connections = connections; + this.uptime = uptime; + this.configuredTickRate = configuredTickRate; + this.actualTickRate = actualTickRate; + + // traffic + this.sentBytesPerSecond = sentBytesPerSecond; + this.receiveBytesPerSecond = receiveBytesPerSecond; + + // cpu + this.serverTickInterval = serverTickInterval; + this.fullUpdateAvg = fullUpdateAvg; + this.serverEarlyAvg = serverEarlyAvg; + this.serverLateAvg = serverLateAvg; + this.transportEarlyAvg = transportEarlyAvg; + this.transportLateAvg = transportLateAvg; + } + } + + // [RequireComponent(typeof(NetworkStatistics))] <- needs to be on Network GO, not on NI + public class RemoteStatistics : NetworkBehaviour + { + // components ("fake statics" for similar API) + protected NetworkStatistics NetworkStatistics; + + // broadcast to client. + // stats are quite huge, let's only send every few seconds via TargetRpc. + // instead of sending multiple times per second via NB.OnSerialize. + [Tooltip("Send stats every 'interval' seconds to client.")] + public float sendInterval = 1; + double lastSendTime; + + [Header("GUI")] + public bool showGui; + public KeyCode hotKey = KeyCode.BackQuote; + Rect windowRect = new Rect(0, 0, 400, 400); + + // password can't be stored in code or in Unity project. + // it would be available in clients otherwise. + // this is not perfectly secure. that's why RemoteStatistics is read-only. + [Header("Authentication")] + public string passwordFile = "remote_statistics.txt"; + protected bool serverAuthenticated; // client needs to authenticate + protected bool clientAuthenticated; // show GUI until authenticated + protected string serverPassword = null; // null means not found, auth impossible + protected string clientPassword = ""; // for GUI + + // statistics synced to client + Stats stats; + + void LoadPassword() + { + // TODO only load once, not for all players? + // let's avoid static state for now. + + // load the password + string path = Path.GetFullPath(passwordFile); + if (File.Exists(path)) + { + // don't spam the server logs for every player's loaded file + // Debug.Log($"RemoteStatistics: loading password file: {path}"); + try + { + serverPassword = File.ReadAllText(path); + } + catch (Exception exception) + { + Debug.LogWarning($"RemoteStatistics: failed to read password file: {exception}"); + } + } + else + { + Debug.LogWarning($"RemoteStatistics: password file has not been created. Authentication will be impossible. Please save the password in: {path}"); + } + } + + protected override void OnValidate() + { + base.OnValidate(); + syncMode = SyncMode.Owner; + } + + // make sure to call base function when overwriting! + // public so it can also be called from tests (and be overwritten by users) + public override void OnStartServer() + { + NetworkStatistics = NetworkManager.singleton.GetComponent(); + if (NetworkStatistics == null) throw new Exception($"RemoteStatistics requires a NetworkStatistics component on {NetworkManager.singleton.name}!"); + + // server needs to load the password + LoadPassword(); + } + + public override void OnStartLocalPlayer() + { + // center the window initially + windowRect.x = Screen.width / 2 - windowRect.width / 2; + windowRect.y = Screen.height / 2 - windowRect.height / 2; + } + + [TargetRpc] + void TargetRpcSync(Stats v) + { + // store stats and flag as authenticated + clientAuthenticated = true; + stats = v; + } + + [Command] + public void CmdAuthenticate(string v) + { + // was a valid password loaded on the server, + // and did the client send the correct one? + if (!string.IsNullOrWhiteSpace(serverPassword) && + serverPassword.Equals(v)) + { + serverAuthenticated = true; + Debug.Log($"RemoteStatistics: connectionId {connectionToClient.connectionId} authenticated with player {name}"); + } + } + + void UpdateServer() + { + // only sync if client has authenticated on the server + if (!serverAuthenticated) return; + + // NetworkTime.localTime has defines for 2019 / 2020 compatibility + if (NetworkTime.localTime >= lastSendTime + sendInterval) + { + lastSendTime = NetworkTime.localTime; + + // target rpc to owner client + TargetRpcSync(new Stats( + // general + NetworkServer.connections.Count, + NetworkTime.time, + NetworkServer.tickRate, + NetworkServer.actualTickRate, + + // traffic + NetworkStatistics.serverSentBytesPerSecond, + NetworkStatistics.serverReceivedBytesPerSecond, + + // cpu + NetworkServer.tickInterval, + NetworkServer.fullUpdateDuration.average, + NetworkServer.earlyUpdateDuration.average, + NetworkServer.lateUpdateDuration.average, + 0, // TODO ServerTransport.earlyUpdateDuration.average, + 0 // TODO ServerTransport.lateUpdateDuration.average + )); + } + } + + void UpdateClient() + { + if (Input.GetKeyDown(hotKey)) + showGui = !showGui; + } + + void Update() + { + if (isServer) UpdateServer(); + if (isLocalPlayer) UpdateClient(); + } + + void OnGUI() + { + if (!isLocalPlayer) return; + if (!showGui) return; + + windowRect = GUILayout.Window(0, windowRect, OnWindow, "Remote Statistics"); + windowRect = Utils.KeepInScreen(windowRect); + } + + // Text: value + void GUILayout_TextAndValue(string text, string value) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(text); + GUILayout.FlexibleSpace(); + GUILayout.Label(value); + GUILayout.EndHorizontal(); + } + + // fake a progress bar via horizontal scroll bar with ratio as width + void GUILayout_ProgressBar(double ratio, int width) + { + // clamp ratio, otherwise >1 would make it extremely large + ratio = Mathd.Clamp01(ratio); + GUILayout.HorizontalScrollbar(0, (float)ratio, 0, 1, GUILayout.Width(width)); + } + + // need to specify progress bar & caption width, + // otherwise differently sized captions would always misalign the + // progress bars. + void GUILayout_TextAndProgressBar(string text, double ratio, int progressbarWidth, string caption, int captionWidth, Color captionColor) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(text); + GUILayout.FlexibleSpace(); + GUILayout_ProgressBar(ratio, progressbarWidth); + + // coloring the caption is enough. otherwise it's too much. + GUI.color = captionColor; + GUILayout.Label(caption, GUILayout.Width(captionWidth)); + GUI.color = Color.white; + + GUILayout.EndHorizontal(); + } + + void GUI_Authenticate() + { + GUILayout.BeginVertical("Box"); // start general + GUILayout.Label("Authentication"); + + // warning if insecure connection + // if (ClientTransport.IsEncrypted()) + // { + // GUILayout.Label("Connection is encrypted!"); + // } + // else + // { + GUILayout.Label("Connection is not encrypted. Use with care!"); + // } + + // input + clientPassword = GUILayout.PasswordField(clientPassword, '*'); + + // button + GUI.enabled = !string.IsNullOrWhiteSpace(clientPassword); + if (GUILayout.Button("Authenticate")) + { + CmdAuthenticate(clientPassword); + } + GUI.enabled = true; + + GUILayout.EndVertical(); // end general + } + + void GUI_General( + int connections, + double uptime, + int configuredTickRate, + int actualTickRate) + { + GUILayout.BeginVertical("Box"); // start general + GUILayout.Label("General"); + + // connections + GUILayout_TextAndValue("Connections:", $"{connections}"); + + // uptime + GUILayout_TextAndValue("Uptime:", $"{Utils.PrettySeconds(uptime)}"); // TODO + + // tick rate + // might be lower under heavy load. + // might be higher in editor if targetFrameRate can't be set. + GUI.color = actualTickRate < configuredTickRate ? Color.red : Color.green; + GUILayout_TextAndValue("Tick Rate:", $"{actualTickRate} Hz / {configuredTickRate} Hz"); + GUI.color = Color.white; + + GUILayout.EndVertical(); // end general + } + + void GUI_Traffic( + long serverSentBytesPerSecond, + long serverReceivedBytesPerSecond) + { + GUILayout.BeginVertical("Box"); + GUILayout.Label("Network"); + + GUILayout_TextAndValue("Outgoing:", $"{Utils.PrettyBytes(serverSentBytesPerSecond) }/s"); + GUILayout_TextAndValue("Incoming:", $"{Utils.PrettyBytes(serverReceivedBytesPerSecond)}/s"); + + GUILayout.EndVertical(); + } + + void GUI_Cpu( + float serverTickInterval, + double fullUpdateAvg, + double serverEarlyAvg, + double serverLateAvg, + double transportEarlyAvg, + double transportLateAvg) + { + const int barWidth = 120; + const int captionWidth = 90; + + GUILayout.BeginVertical("Box"); + GUILayout.Label("CPU"); + + // unity update + // happens every 'tickInterval'. progress bar shows it in relation. + // <= 90% load is green, otherwise red + double fullRatio = fullUpdateAvg / serverTickInterval; + GUILayout_TextAndProgressBar( + "World Update Avg:", + fullRatio, + barWidth, $"{fullUpdateAvg * 1000:F1} ms", + captionWidth, + fullRatio <= 0.9 ? Color.green : Color.red); + + // server update + // happens every 'tickInterval'. progress bar shows it in relation. + // <= 90% load is green, otherwise red + double serverRatio = (serverEarlyAvg + serverLateAvg) / serverTickInterval; + GUILayout_TextAndProgressBar( + "Server Update Avg:", + serverRatio, + barWidth, $"{serverEarlyAvg * 1000:F1} + {serverLateAvg * 1000:F1} ms", + captionWidth, + serverRatio <= 0.9 ? Color.green : Color.red); + + // transport: early + late update milliseconds. + // for threaded transport, this is the thread's update time. + // happens every 'tickInterval'. progress bar shows it in relation. + // <= 90% load is green, otherwise red + // double transportRatio = (transportEarlyAvg + transportLateAvg) / serverTickInterval; + // GUILayout_TextAndProgressBar( + // "Transport Avg:", + // transportRatio, + // barWidth, + // $"{transportEarlyAvg * 1000:F1} + {transportLateAvg * 1000:F1} ms", + // captionWidth, + // transportRatio <= 0.9 ? Color.green : Color.red); + + GUILayout.EndVertical(); + } + + void GUI_Notice() + { + // for security reasons, let's keep this read-only for now. + + // single line keeps input & visuals simple + // GUILayout.BeginVertical("Box"); + // GUILayout.Label("Global Notice"); + // notice = GUILayout.TextField(notice); + // if (GUILayout.Button("Send")) + // { + // // TODO + // } + // GUILayout.EndVertical(); + } + + void OnWindow(int windowID) + { + if (!clientAuthenticated) + { + GUI_Authenticate(); + } + else + { + GUI_General( + stats.connections, + stats.uptime, + stats.configuredTickRate, + stats.actualTickRate + ); + + GUI_Traffic( + stats.sentBytesPerSecond, + stats.receiveBytesPerSecond + ); + + GUI_Cpu( + stats.serverTickInterval, + stats.fullUpdateAvg, + stats.serverEarlyAvg, + stats.serverLateAvg, + stats.transportEarlyAvg, + stats.transportLateAvg + ); + + GUI_Notice(); + } + + // dragable window in any case + GUI.DragWindow(new Rect(0, 0, 10000, 10000)); + } + } +} diff --git a/Assets/Mirror/Components/RemoteStatistics.cs.meta b/Assets/Mirror/Components/RemoteStatistics.cs.meta new file mode 100644 index 0000000..8754194 --- /dev/null +++ b/Assets/Mirror/Components/RemoteStatistics.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ba360e4ff6b44fc6898f56322b90c6c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Components/RemoteStatistics.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core.meta b/Assets/Mirror/Core.meta new file mode 100644 index 0000000..85ee3eb --- /dev/null +++ b/Assets/Mirror/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f4328ccc5f724e45afe2215d275b5d5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/AssemblyInfo.cs b/Assets/Mirror/Core/AssemblyInfo.cs new file mode 100644 index 0000000..a9c6442 --- /dev/null +++ b/Assets/Mirror/Core/AssemblyInfo.cs @@ -0,0 +1,13 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Mirror.Tests.Common")] +[assembly: InternalsVisibleTo("Mirror.Tests")] +// need to use Unity.*.CodeGen assembly name to import Unity.CompilationPipeline +// for ILPostProcessor tests. +[assembly: InternalsVisibleTo("Unity.Mirror.Tests.CodeGen")] +[assembly: InternalsVisibleTo("Mirror.Tests.Generated")] +[assembly: InternalsVisibleTo("Mirror.Tests.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Editor")] +[assembly: InternalsVisibleTo("Mirror.Tests.Performance.Runtime")] +[assembly: InternalsVisibleTo("Mirror.Editor")] +[assembly: InternalsVisibleTo("Mirror.Components")] diff --git a/Assets/Mirror/Core/AssemblyInfo.cs.meta b/Assets/Mirror/Core/AssemblyInfo.cs.meta new file mode 100644 index 0000000..879e6d0 --- /dev/null +++ b/Assets/Mirror/Core/AssemblyInfo.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e28d5f410e25b42e6a76a2ffc10e4675 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/AssemblyInfo.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Attributes.cs b/Assets/Mirror/Core/Attributes.cs new file mode 100644 index 0000000..53114b4 --- /dev/null +++ b/Assets/Mirror/Core/Attributes.cs @@ -0,0 +1,101 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + /// + /// SyncVars are used to automatically synchronize a variable between the server and all clients. The direction of synchronization depends on the Sync Direction property, ServerToClient by default. + /// + /// When Sync Direction is equal to ServerToClient, the value should be changed on the server side and synchronized to all clients. + /// Otherwise, the value should be changed on the client side and synchronized to server and other clients. + /// + /// Hook parameter allows you to define a method to be invoked when gets an value update. Notice that the hook method will not be called on the change side. + /// + [AttributeUsage(AttributeTargets.Field)] + public class SyncVarAttribute : PropertyAttribute + { + public string hook; + } + + /// + /// Call this from a client to run this function on the server. + /// Make sure to validate input etc. It's not possible to call this from a server. + /// + [AttributeUsage(AttributeTargets.Method)] + public class CommandAttribute : Attribute + { + public int channel = Channels.Reliable; + public bool requiresAuthority = true; + } + + /// + /// The server uses a Remote Procedure Call (RPC) to run this function on clients. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ClientRpcAttribute : Attribute + { + public int channel = Channels.Reliable; + public bool includeOwner = true; + } + + /// + /// The server uses a Remote Procedure Call (RPC) to run this function on a specific client. + /// + [AttributeUsage(AttributeTargets.Method)] + public class TargetRpcAttribute : Attribute + { + public int channel = Channels.Reliable; + } + + /// + /// Only an active server will run this method. + /// Prints a warning if a client or in-active server tries to execute this method. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ServerAttribute : Attribute {} + + /// + /// Only an active server will run this method. + /// No warning is thrown. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ServerCallbackAttribute : Attribute {} + + /// + /// Only an active client will run this method. + /// Prints a warning if the server or in-active client tries to execute this method. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ClientAttribute : Attribute {} + + /// + /// Only an active client will run this method. + /// No warning is printed. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ClientCallbackAttribute : Attribute {} + + /// + /// Converts a string property into a Scene property in the inspector + /// + public class SceneAttribute : PropertyAttribute {} + + /// + /// Used to show private SyncList in the inspector, + /// Use instead of SerializeField for non Serializable types + /// + [AttributeUsage(AttributeTargets.Field)] + public class ShowInInspectorAttribute : Attribute {} + + /// + /// Used to make a field readonly in the inspector + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ReadOnlyAttribute : PropertyAttribute {} + + /// + /// When defining multiple Readers/Writers for the same type, indicate which one Weaver must use. + /// + [AttributeUsage(AttributeTargets.Method)] + public class WeaverPriorityAttribute : Attribute {} +} diff --git a/Assets/Mirror/Core/Attributes.cs.meta b/Assets/Mirror/Core/Attributes.cs.meta new file mode 100644 index 0000000..09a8b6f --- /dev/null +++ b/Assets/Mirror/Core/Attributes.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c04c722ee2ffd49c8a56ab33667b10b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Attributes.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Batching.meta b/Assets/Mirror/Core/Batching.meta new file mode 100644 index 0000000..bf23600 --- /dev/null +++ b/Assets/Mirror/Core/Batching.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c38e1bebe9947f8b842a8a57aa2b71c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Batching/Batcher.cs b/Assets/Mirror/Core/Batching/Batcher.cs new file mode 100644 index 0000000..6f7cad9 --- /dev/null +++ b/Assets/Mirror/Core/Batching/Batcher.cs @@ -0,0 +1,206 @@ +// batching functionality encapsulated into one class. +// -> less complexity +// -> easy to test +// +// IMPORTANT: we use THRESHOLD batching, not MAXED SIZE batching. +// see threshold comments below. +// +// includes timestamp for tick batching. +// -> allows NetworkTransform etc. to use timestamp without including it in +// every single message +using System; +using System.Collections.Generic; + +namespace Mirror +{ + public class Batcher + { + // batching threshold instead of max size. + // -> small messages are fit into threshold sized batches + // -> messages larger than threshold are single batches + // + // in other words, we fit up to 'threshold' but still allow larger ones + // for two reasons: + // 1.) data races: skipping batching for larger messages would send a + // large spawn message immediately, while others are batched and + // only flushed at the end of the frame + // 2) timestamp batching: if each batch is expected to contain a + // timestamp, then large messages have to be a batch too. otherwise + // they would not contain a timestamp + readonly int threshold; + + // TimeStamp header size. each batch has one. + public const int TimestampSize = sizeof(double); + + // Message header size. each message has one. + public static int MessageHeaderSize(int messageSize) => + Compression.VarUIntSize((ulong)messageSize); + + // maximum overhead for a single message. + // useful for the outside to calculate max message sizes. + public static int MaxMessageOverhead(int messageSize) => + TimestampSize + MessageHeaderSize(messageSize); + + // full batches ready to be sent. + // DO NOT queue NetworkMessage, it would box. + // DO NOT queue each serialization separately. + // it would allocate too many writers. + // https://github.com/vis2k/Mirror/pull/3127 + // => best to build batches on the fly. + readonly Queue batches = new Queue(); + + // current batch in progress. + // we also store the timestamp to ensure we don't add a message from another frame, + // as this would introduce subtle jitter! + // + // for example: + // - a batch is started at t=1, another message is added at t=2 and then it's flushed + // - NetworkTransform uses remoteTimestamp which is t=1 + // - snapshot interpolation would off by one (or multiple) frames! + NetworkWriterPooled batch; + double batchTimestamp; + + public Batcher(int threshold) + { + this.threshold = threshold; + } + + // add a message for batching + // we allow any sized messages. + // caller needs to make sure they are within max packet size. + public void AddMessage(ArraySegment message, double timeStamp) + { + // safety: message timestamp is only written once. + // make sure all messages in this batch are from the same timestamp. + // otherwise it could silently introduce jitter. + // + // this happened before: + // - NetworkEarlyUpdate @ t=1 processes transport messages + // - a handler replies by sending a message + // - a new batch is started @ t=1, timestamp is encoded + // - NetworkLateUpdate @ t=2 decides it's time to broadcast + // - NetworkTransform sends @ t=2 + // - we add to the above batch which already encoded t=1 + // - Client receives the batch which timestamp t=1 + // - NetworkTransform uses remoteTime for interpolation + // remoteTime is the batch timestamp which is t=1 + // - the NetworkTransform message is actually t=2 + // => smooth interpolation would be impossible! + // NT thinks the position was @ t=1 but actually it was @ t=2 ! + // + // the solution: if timestamp changed, enqueue the existing batch + if (batch != null && batchTimestamp != timeStamp) + { + batches.Enqueue(batch); + batch = null; + batchTimestamp = 0; + } + + // predict the needed size, which is varint(size) + content + int headerSize = Compression.VarUIntSize((ulong)message.Count); + int neededSize = headerSize + message.Count; + + // when appending to a batch in progress, check final size. + // if it expands beyond threshold, then we should finalize it first. + // => less than or exactly threshold is fine. + // GetBatch() will finalize it. + // => see unit tests. + if (batch != null && + batch.Position + neededSize > threshold) + { + batches.Enqueue(batch); + batch = null; + batchTimestamp = 0; + } + + // initialize a new batch if necessary + if (batch == null) + { + // borrow from pool. we return it in GetBatch. + batch = NetworkWriterPool.Get(); + + // write timestamp first. + // -> double precision for accuracy over long periods of time + // -> batches are per-frame, it doesn't matter which message's + // timestamp we use. + batch.WriteDouble(timeStamp); + + // remember the encoded timestamp, see safety check below. + batchTimestamp = timeStamp; + } + + // add serialization to current batch. even if > threshold. + // -> we do allow > threshold sized messages as single batch + // -> WriteBytes instead of WriteSegment because the latter + // would add a size header. we want to write directly. + // + // include size prefix as varint! + // -> fixes NetworkMessage serialization mismatch corrupting the + // next message in a batch. + // -> a _lot_ of time was wasted debugging corrupt batches. + // no easy way to figure out which NetworkMessage has a mismatch. + // -> this is worth everyone's sanity. + // -> varint means we prefix with 1 byte most of the time. + // -> the same issue in NetworkIdentity was why Mirror started! + Compression.CompressVarUInt(batch, (ulong)message.Count); + batch.WriteBytes(message.Array, message.Offset, message.Count); + } + + // helper function to copy a batch to writer and return it to pool + static void CopyAndReturn(NetworkWriterPooled batch, NetworkWriter writer) + { + // make sure the writer is fresh to avoid uncertain situations + if (writer.Position != 0) + throw new ArgumentException($"GetBatch needs a fresh writer!"); + + // copy to the target writer + ArraySegment segment = batch.ToArraySegment(); + writer.WriteBytes(segment.Array, segment.Offset, segment.Count); + + // return batch to pool for reuse + NetworkWriterPool.Return(batch); + } + + // get the next batch which is available for sending (if any). + // TODO safely get & return a batch instead of copying to writer? + // TODO could return pooled writer & use GetBatch in a 'using' statement! + public bool GetBatch(NetworkWriter writer) + { + // get first batch from queue (if any) + if (batches.TryDequeue(out NetworkWriterPooled first)) + { + CopyAndReturn(first, writer); + return true; + } + + // if queue was empty, we can send the batch in progress. + if (batch != null) + { + CopyAndReturn(batch, writer); + batch = null; + return true; + } + + // nothing was written + return false; + } + + // return all batches to the pool for cleanup + public void Clear() + { + // return batch in progress + if (batch != null) + { + NetworkWriterPool.Return(batch); + batch = null; + batchTimestamp = 0; + } + + // return all queued batches + foreach (NetworkWriterPooled queued in batches) + NetworkWriterPool.Return(queued); + + batches.Clear(); + } + } +} diff --git a/Assets/Mirror/Core/Batching/Batcher.cs.meta b/Assets/Mirror/Core/Batching/Batcher.cs.meta new file mode 100644 index 0000000..2449b26 --- /dev/null +++ b/Assets/Mirror/Core/Batching/Batcher.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0afaaa611a2142d48a07bdd03b68b2b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Batching/Batcher.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Batching/Unbatcher.cs b/Assets/Mirror/Core/Batching/Unbatcher.cs new file mode 100644 index 0000000..6b2c405 --- /dev/null +++ b/Assets/Mirror/Core/Batching/Unbatcher.cs @@ -0,0 +1,129 @@ +// un-batching functionality encapsulated into one class. +// -> less complexity +// -> easy to test +// +// includes timestamp for tick batching. +// -> allows NetworkTransform etc. to use timestamp without including it in +// every single message +using System; +using System.Collections.Generic; + +namespace Mirror +{ + public class Unbatcher + { + // supporting adding multiple batches before GetNextMessage is called. + // just in case. + readonly Queue batches = new Queue(); + + public int BatchesCount => batches.Count; + + // NetworkReader is only created once, + // then pointed to the first batch. + readonly NetworkReader reader = new NetworkReader(new byte[0]); + + // timestamp that was written into the batch remotely. + // for the batch that our reader is currently pointed at. + double readerRemoteTimeStamp; + + // helper function to start reading a batch. + void StartReadingBatch(NetworkWriterPooled batch) + { + // point reader to it + reader.SetBuffer(batch.ToArraySegment()); + + // read remote timestamp (double) + // -> AddBatch quarantees that we have at least 8 bytes to read + readerRemoteTimeStamp = reader.ReadDouble(); + } + + // add a new batch. + // returns true if valid. + // returns false if not, in which case the connection should be disconnected. + public bool AddBatch(ArraySegment batch) + { + // IMPORTANT: ArraySegment is only valid until returning. we copy it! + // + // NOTE: it's not possible to create empty ArraySegments, so we + // don't need to check against that. + + // make sure we have at least 8 bytes to read for tick timestamp + if (batch.Count < Batcher.TimestampSize) + return false; + + // put into a (pooled) writer + // -> WriteBytes instead of WriteSegment because the latter + // would add a size header. we want to write directly. + // -> will be returned to pool when sending! + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.WriteBytes(batch.Array, batch.Offset, batch.Count); + + // first batch? then point reader there + if (batches.Count == 0) + StartReadingBatch(writer); + + // add batch + batches.Enqueue(writer); + //Debug.Log($"Adding Batch {BitConverter.ToString(batch.Array, batch.Offset, batch.Count)} => batches={batches.Count} reader={reader}"); + return true; + } + + // get next message, unpacked from batch (if any) + // message ArraySegment is only valid until the next call. + // timestamp is the REMOTE time when the batch was created remotely. + public bool GetNextMessage(out ArraySegment message, out double remoteTimeStamp) + { + message = default; + remoteTimeStamp = 0; + + // do nothing if we don't have any batches. + // otherwise the below queue.Dequeue() would throw an + // InvalidOperationException if operating on empty queue. + if (batches.Count == 0) + return false; + + // was our reader pointed to anything yet? + if (reader.Capacity == 0) + return false; + + // no more data to read? + if (reader.Remaining == 0) + { + // retire the batch + NetworkWriterPooled writer = batches.Dequeue(); + NetworkWriterPool.Return(writer); + + // do we have another batch? + if (batches.Count > 0) + { + // point reader to the next batch. + // we'll return the reader below. + NetworkWriterPooled next = batches.Peek(); + StartReadingBatch(next); + } + // otherwise there's nothing more to read + else return false; + } + + // use the current batch's remote timestamp + // AFTER potentially moving to the next batch ABOVE! + remoteTimeStamp = readerRemoteTimeStamp; + + // enough data to read the size prefix? + if (reader.Remaining == 0) + return false; + + // read the size prefix as varint + // see Batcher.AddMessage comments for explanation. + int size = (int)Compression.DecompressVarUInt(reader); + + // validate size prefix, in case attackers send malicious data + if (reader.Remaining < size) + return false; + + // return the message of size + message = reader.ReadBytesSegment(size); + return true; + } + } +} diff --git a/Assets/Mirror/Core/Batching/Unbatcher.cs.meta b/Assets/Mirror/Core/Batching/Unbatcher.cs.meta new file mode 100644 index 0000000..a2d8dfa --- /dev/null +++ b/Assets/Mirror/Core/Batching/Unbatcher.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 328562d71e1c45c58581b958845aa7a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Batching/Unbatcher.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/ConnectionQuality.cs b/Assets/Mirror/Core/ConnectionQuality.cs new file mode 100644 index 0000000..9989f87 --- /dev/null +++ b/Assets/Mirror/Core/ConnectionQuality.cs @@ -0,0 +1,74 @@ +// standalone, Unity-independent connection-quality algorithm & enum. +// don't need to use this directly, it's built into Mirror's NetworkClient. +using UnityEngine; + +namespace Mirror +{ + public enum ConnectionQuality : byte + { + ESTIMATING, // still estimating + POOR, // unplayable + FAIR, // very noticeable latency, not very enjoyable anymore + GOOD, // very playable for everyone but high level competitors + EXCELLENT // ideal experience for high level competitors + } + + public enum ConnectionQualityMethod : byte + { + Simple, // simple estimation based on rtt and jitter + Pragmatic // based on snapshot interpolation adjustment + } + + // provide different heuristics for users to choose from. + // simple heuristics to get started. + // this will be iterated on over time based on user feedback. + public static class ConnectionQualityHeuristics + { + // convenience extension to color code Connection Quality + public static Color ColorCode(this ConnectionQuality quality) + { + switch (quality) + { + case ConnectionQuality.POOR: return Color.red; + case ConnectionQuality.FAIR: return new Color(1.0f, 0.647f, 0.0f); + case ConnectionQuality.GOOD: return Color.yellow; + case ConnectionQuality.EXCELLENT: return Color.green; + default: return Color.gray; // ESTIMATING + } + } + + // straight forward estimation + // rtt: average round trip time in seconds. + // jitter: average latency variance. + public static ConnectionQuality Simple(double rtt, double jitter) + { + if (rtt <= 0.100 && jitter <= 0.10) return ConnectionQuality.EXCELLENT; + if (rtt <= 0.200 && jitter <= 0.20) return ConnectionQuality.GOOD; + if (rtt <= 0.400 && jitter <= 0.50) return ConnectionQuality.FAIR; + return ConnectionQuality.POOR; + } + + // snapshot interpolation based estimation. + // snap. interp. adjusts buffer time based on connection quality. + // based on this, we can measure how far away we are from the ideal. + // the returned quality will always directly correlate with gameplay. + // => requires SnapshotInterpolation dynamicAdjustment to be enabled! + public static ConnectionQuality Pragmatic(double targetBufferTime, double currentBufferTime) + { + // buffer time is set by the game developer. + // estimating in multiples is a great way to be game independent. + // for example, a fast paced shooter and a slow paced RTS will both + // have poor connection if the multiplier is >10. + double multiplier = currentBufferTime / targetBufferTime; + + // empirically measured with Tanks demo + LatencySimulation. + // it's not obvious to estimate on paper. + if (multiplier <= 1.15) return ConnectionQuality.EXCELLENT; + if (multiplier <= 1.25) return ConnectionQuality.GOOD; + if (multiplier <= 1.50) return ConnectionQuality.FAIR; + + // anything else is poor + return ConnectionQuality.POOR; + } + } +} diff --git a/Assets/Mirror/Core/ConnectionQuality.cs.meta b/Assets/Mirror/Core/ConnectionQuality.cs.meta new file mode 100644 index 0000000..50eddb3 --- /dev/null +++ b/Assets/Mirror/Core/ConnectionQuality.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ff663b880e33e4606b545c8b497041c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/ConnectionQuality.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/HostMode.cs b/Assets/Mirror/Core/HostMode.cs new file mode 100644 index 0000000..3054b3c --- /dev/null +++ b/Assets/Mirror/Core/HostMode.cs @@ -0,0 +1,44 @@ +// host mode related helper functions. +// usually they set up both server & client. +// it's cleaner to keep them in one place, instead of only in server / client. +using System; + +namespace Mirror +{ + public static class HostMode + { + // keep the local connections setup in one function. + // makes host setup easier to follow. + internal static void SetupConnections() + { + // create local connections pair, both are connected + Utils.CreateLocalConnections( + out LocalConnectionToClient connectionToClient, + out LocalConnectionToServer connectionToServer); + + // set client connection + NetworkClient.connection = connectionToServer; + + // set server connection + NetworkServer.SetLocalConnection(connectionToClient); + } + + // call OnConnected on server & client. + // public because NetworkClient.ConnectLocalServer was public before too. + public static void InvokeOnConnected() + { + // call server OnConnected with server's connection to client + NetworkServer.OnConnected(NetworkServer.localConnection); + + // call client OnConnected with client's connection to server + // => previously we used to send a ConnectMessage to + // NetworkServer.localConnection. this would queue the message + // until NetworkClient.Update processes it. + // => invoking the client's OnConnected event directly here makes + // tests fail. so let's do it exactly the same order as before by + // queueing the event for next Update! + //OnConnectedEvent?.Invoke(connection); + ((LocalConnectionToServer)NetworkClient.connection).QueueConnectedEvent(); + } + } +} diff --git a/Assets/Mirror/Core/HostMode.cs.meta b/Assets/Mirror/Core/HostMode.cs.meta new file mode 100644 index 0000000..6e10676 --- /dev/null +++ b/Assets/Mirror/Core/HostMode.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d27175a08d5341fc97645b49ee533d5a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/HostMode.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/InterestManagement.cs b/Assets/Mirror/Core/InterestManagement.cs new file mode 100644 index 0000000..88ead0f --- /dev/null +++ b/Assets/Mirror/Core/InterestManagement.cs @@ -0,0 +1,146 @@ +// interest management component for custom solutions like +// distance based, spatial hashing, raycast based, etc. + +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public abstract class InterestManagement : InterestManagementBase + { + // allocate newObservers helper HashSet + readonly HashSet newObservers = + new HashSet(); + + // rebuild observers for the given NetworkIdentity. + // Server will automatically spawn/despawn added/removed ones. + // newObservers: cached hashset to put the result into + // initialize: true if being rebuilt for the first time + // + // IMPORTANT: + // => global rebuild would be more simple, BUT + // => local rebuild is way faster for spawn/despawn because we can + // simply rebuild a select NetworkIdentity only + // => having both .observers and .observing is necessary for local + // rebuilds + // + // in other words, this is the perfect solution even though it's not + // completely simple (due to .observers & .observing). + // + // Mirror maintains .observing automatically in the background. best of + // both worlds without any worrying now! + public abstract void OnRebuildObservers(NetworkIdentity identity, HashSet newObservers); + + // helper function to trigger a full rebuild. + // most implementations should call this in a certain interval. + // some might call this all the time, or only on team changes or + // scene changes and so on. + // + // IMPORTANT: check if NetworkServer.active when using Update()! + [ServerCallback] + protected void RebuildAll() + { + foreach (NetworkIdentity identity in NetworkServer.spawned.Values) + { + NetworkServer.RebuildObservers(identity, false); + } + } + + public override void Rebuild(NetworkIdentity identity, bool initialize) + { + // clear newObservers hashset before using it + newObservers.Clear(); + + // not force hidden? + if (identity.visibility != Visibility.ForceHidden) + { + OnRebuildObservers(identity, newObservers); + } + + // IMPORTANT: AFTER rebuilding add own player connection in any case + // to ensure player always sees himself no matter what. + // -> OnRebuildObservers might clear observers, so we need to add + // the player's own connection AFTER. 100% fail safe. + // -> fixes https://github.com/vis2k/Mirror/issues/692 where a + // player might teleport out of the ProximityChecker's cast, + // losing the own connection as observer. + if (identity.connectionToClient != null) + { + newObservers.Add(identity.connectionToClient); + } + + bool changed = false; + + // add all newObservers that aren't in .observers yet + foreach (NetworkConnectionToClient conn in newObservers) + { + // only add ready connections. + // otherwise the player might not be in the world yet or anymore + if (conn != null && conn.isReady) + { + if (initialize || !identity.observers.ContainsKey(conn.connectionId)) + { + // new observer + conn.AddToObserving(identity); + // Debug.Log($"New Observer for {gameObject} {conn}"); + changed = true; + } + } + } + + // remove all old .observers that aren't in newObservers anymore + foreach (NetworkConnectionToClient conn in identity.observers.Values) + { + if (!newObservers.Contains(conn)) + { + // removed observer + conn.RemoveFromObserving(identity, false); + // Debug.Log($"Removed Observer for {gameObject} {conn}"); + changed = true; + } + } + + // copy new observers to observers + if (changed) + { + identity.observers.Clear(); + foreach (NetworkConnectionToClient conn in newObservers) + { + if (conn != null && conn.isReady) + identity.observers.Add(conn.connectionId, conn); + } + } + + // special case for host mode: we use SetHostVisibility to hide + // NetworkIdentities that aren't in observer range from host. + // this is what games like Dota/Counter-Strike do too, where a host + // does NOT see all players by default. they are in memory, but + // hidden to the host player. + // + // this code is from UNET, it's a bit strange but it works: + // * it hides newly connected identities in host mode + // => that part was the intended behaviour + // * it hides ALL NetworkIdentities in host mode when the host + // connects but hasn't selected a character yet + // => this only works because we have no .localConnection != null + // check. at this stage, localConnection is null because + // StartHost starts the server first, then calls this code, + // then starts the client and sets .localConnection. so we can + // NOT add a null check without breaking host visibility here. + // * it hides ALL NetworkIdentities in server-only mode because + // observers never contain the 'null' .localConnection + // => that was not intended, but let's keep it as it is so we + // don't break anything in host mode. it's way easier than + // iterating all identities in a special function in StartHost. + if (initialize) + { + if (!newObservers.Contains(NetworkServer.localConnection)) + { + SetHostVisibility(identity, false); + } + } + } + } +} diff --git a/Assets/Mirror/Core/InterestManagement.cs.meta b/Assets/Mirror/Core/InterestManagement.cs.meta new file mode 100644 index 0000000..a13677b --- /dev/null +++ b/Assets/Mirror/Core/InterestManagement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 41d809934003479f97e992eebb7ed6af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/InterestManagement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/InterestManagementBase.cs b/Assets/Mirror/Core/InterestManagementBase.cs new file mode 100644 index 0000000..1a3cc1b --- /dev/null +++ b/Assets/Mirror/Core/InterestManagementBase.cs @@ -0,0 +1,103 @@ +// interest management component for custom solutions like +// distance based, spatial hashing, raycast based, etc. +// low level base class allows for low level spatial hashing etc., which is 3-5x faster. +using UnityEngine; + +namespace Mirror +{ + [DisallowMultipleComponent] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")] + public abstract class InterestManagementBase : MonoBehaviour + { + // initialize NetworkServer/Client .aoi. + // previously we did this in Awake(), but that's called for disabled + // components too. if we do it OnEnable(), then it's not set for + // disabled components. + protected virtual void OnEnable() + { + // do not check if == null or error if already set. + // users may enabled/disable components randomly, + // causing this to be called multiple times. + NetworkServer.aoi = this; + NetworkClient.aoi = this; + } + + [ServerCallback] + public virtual void ResetState() {} + + // Callback used by the visibility system to determine if an observer + // (player) can see the NetworkIdentity. If this function returns true, + // the network connection will be added as an observer. + // conn: Network connection of a player. + // returns True if the player can see this object. + public abstract bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver); + + + // Callback used by the visibility system for objects on a host. + // Objects on a host (with a local client) cannot be disabled or + // destroyed when they are not visible to the local client. So this + // function is called to allow custom code to hide these objects. A + // typical implementation will disable renderer components on the + // object. This is only called on local clients on a host. + // => need the function in here and virtual so people can overwrite! + // => not everyone wants to hide renderers! + [ServerCallback] + public virtual void SetHostVisibility(NetworkIdentity identity, bool visible) + { + foreach (Renderer rend in identity.GetComponentsInChildren()) + rend.enabled = visible; + + // reason to also set lights/audio/terrain/etc.: + // Let's say players were holding a flashlight or magic wand with a particle effect. Without this, + // host client would see the light / particles for all players in all subscenes because we don't + // hide lights and particles. Host client would hear ALL audio sources in all subscenes too. We + // hide the renderers, which covers basic objects and UI, but we don't hide anything else that may + // be a child of a networked object. Same idea for cars with lights and sounds in other subscenes + // that host client shouldn't see or hear...host client wouldn't see the car itself, but sees the + // lights moving around and hears all of their engines / horns / etc. + foreach (Light light in identity.GetComponentsInChildren()) + light.enabled = visible; + + foreach (AudioSource audio in identity.GetComponentsInChildren()) + audio.enabled = visible; + + foreach (Terrain terrain in identity.GetComponentsInChildren()) + { + terrain.drawHeightmap = visible; + terrain.drawTreesAndFoliage = visible; + } + + foreach (ParticleSystem particle in identity.GetComponentsInChildren()) + { + ParticleSystem.EmissionModule emission = particle.emission; + emission.enabled = visible; + } + } + + /// Called on the server when a new networked object is spawned. + // (useful for 'only rebuild if changed' interest management algorithms) + [ServerCallback] + public virtual void OnSpawned(NetworkIdentity identity) {} + + /// Called on the server when a networked object is destroyed. + // (useful for 'only rebuild if changed' interest management algorithms) + [ServerCallback] + public virtual void OnDestroyed(NetworkIdentity identity) {} + + public abstract void Rebuild(NetworkIdentity identity, bool initialize); + + /// Adds the specified connection to the observers of identity + protected void AddObserver(NetworkConnectionToClient connection, NetworkIdentity identity) + { + connection.AddToObserving(identity); + identity.observers.Add(connection.connectionId, connection); + } + + /// Removes the specified connection from the observers of identity + protected void RemoveObserver(NetworkConnectionToClient connection, NetworkIdentity identity) + { + connection.RemoveFromObserving(identity, false); + identity.observers.Remove(connection.connectionId); + } + } +} diff --git a/Assets/Mirror/Core/InterestManagementBase.cs.meta b/Assets/Mirror/Core/InterestManagementBase.cs.meta new file mode 100644 index 0000000..257afc4 --- /dev/null +++ b/Assets/Mirror/Core/InterestManagementBase.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 18bd2ffe65a444f3b13d59bdac7f2228 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/InterestManagementBase.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LagCompensation.meta b/Assets/Mirror/Core/LagCompensation.meta new file mode 100644 index 0000000..3c2b3f9 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d2656015ded44e83a24f4c4776bafd40 +timeCreated: 1687920405 diff --git a/Assets/Mirror/Core/LagCompensation/Capture.cs b/Assets/Mirror/Core/LagCompensation/Capture.cs new file mode 100644 index 0000000..e4fdabe --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/Capture.cs @@ -0,0 +1,13 @@ +namespace Mirror +{ + public interface Capture + { + // server timestamp at time of capture. + double timestamp { get; set; } + + // optional gizmo drawing for visual debugging. + // history is only known on the server, which usually doesn't render. + // showing Gizmos in the Editor is enough. + void DrawGizmo(); + } +} diff --git a/Assets/Mirror/Core/LagCompensation/Capture.cs.meta b/Assets/Mirror/Core/LagCompensation/Capture.cs.meta new file mode 100644 index 0000000..a9cc6cc --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/Capture.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 347e831952e943a49095cadd39a5aeb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LagCompensation/Capture.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs new file mode 100644 index 0000000..29ebc2e --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs @@ -0,0 +1,139 @@ +// HistoryBounds keeps a bounding box of all the object's bounds in the past N seconds. +// useful to decide which objects to rollback, instead of rolling back all of them. +// https://www.youtube.com/watch?v=zrIY0eIyqmI (37:00) +// standalone C# implementation to be engine (and language) agnostic. + +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // FakeByte: gather bounds in smaller buckets. + // for example, bucket(t0,t1,t2), bucket(t3,t4,t5), ... + // instead of removing old bounds t0, t1, ... + // we remove a whole bucket every 3 times: bucket(t0,t1,t2) + // and when building total bounds, we encapsulate a few larger buckets + // instead of many smaller bounds. + // + // => a bucket is encapsulate(bounds0, bounds1, bounds2) so we don't + // need a custom struct, simply reuse bounds but remember that each + // entry includes N timestamps. + // + // => note that simply reducing capture interval is _not_ the same. + // we want to capture in detail in case players run in zig-zag. + // but still grow larger buckets internally. + public class HistoryBounds + { + // mischa: use MinMaxBounds to avoid Unity Bounds.Encapsulate conversions. + readonly int boundsPerBucket; + readonly Queue fullBuckets; + + // full bucket limit. older ones will be removed. + readonly int bucketLimit; + + // bucket in progress, contains 0..boundsPerBucket bounds encapsulated. + MinMaxBounds? currentBucket; + int currentBucketSize; + + // amount of total bounds, including bounds in full buckets + current + public int boundsCount { get; private set; } + + // total bounds encapsulating all of the bounds history. + // totalMinMax is used for internal calculations. + // public total is used for Unity representation. + MinMaxBounds totalMinMax; + public Bounds total + { + get + { + Bounds bounds = new Bounds(); + bounds.SetMinMax(totalMinMax.min, totalMinMax.max); + return bounds; + } + } + + public HistoryBounds(int boundsLimit, int boundsPerBucket) + { + // bucketLimit via '/' cuts off remainder. + // that's what we want, since we always have a 'currentBucket'. + this.boundsPerBucket = boundsPerBucket; + this.bucketLimit = (boundsLimit / boundsPerBucket); + + // initialize queue with maximum capacity to avoid runtime resizing + // capacity +1 because it makes the code easier if we insert first, and then remove. + fullBuckets = new Queue(bucketLimit + 1); + } + + // insert new bounds into history. calculates new total bounds. + // Queue.Dequeue() always has the oldest bounds. + public void Insert(Bounds bounds) + { + // convert to MinMax representation for faster .Encapsulate() + MinMaxBounds minmax = new MinMaxBounds + { + min = bounds.min, + max = bounds.max + }; + + // initialize 'total' if not initialized yet. + // we don't want to call (0,0).Encapsulate(bounds). + if (boundsCount == 0) + { + totalMinMax = minmax; + } + + // add to current bucket: + // either initialize new one, or encapsulate into existing one + if (currentBucket == null) + { + currentBucket = minmax; + } + else + { + currentBucket.Value.Encapsulate(minmax); + } + + // current bucket has one more bounds. + // total bounds increased as well. + currentBucketSize += 1; + boundsCount += 1; + + // always encapsulate into total immediately. + // this is free. + totalMinMax.Encapsulate(minmax); + + // current bucket full? + if (currentBucketSize == boundsPerBucket) + { + // move it to full buckets + fullBuckets.Enqueue(currentBucket.Value); + currentBucket = null; + currentBucketSize = 0; + + // full bucket capacity reached? + if (fullBuckets.Count > bucketLimit) + { + // remove oldest bucket + fullBuckets.Dequeue(); + boundsCount -= boundsPerBucket; + + // recompute total bounds + // instead of iterating N buckets, we iterate N / boundsPerBucket buckets. + // TODO technically we could reuse 'currentBucket' before clearing instead of encapsulating again + totalMinMax = minmax; + foreach (MinMaxBounds bucket in fullBuckets) + totalMinMax.Encapsulate(bucket); + } + } + } + + public void Reset() + { + fullBuckets.Clear(); + currentBucket = null; + currentBucketSize = 0; + boundsCount = 0; + totalMinMax = new MinMaxBounds(); + } + } +} diff --git a/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta new file mode 100644 index 0000000..290df33 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/HistoryBounds.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ca9ea58b98a34f73801b162cd5de724e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LagCompensation/HistoryBounds.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensation.cs b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs new file mode 100644 index 0000000..ae37a3f --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs @@ -0,0 +1,144 @@ +// standalone lag compensation algorithm +// based on the Valve Networking Model: +// https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking +using System.Collections.Generic; + +namespace Mirror +{ + public static class LagCompensation + { + // history is of . + // Queue allows for fast 'remove first' and 'append last'. + // + // make sure to always insert in order. + // inserting out of order like [1,2,4,3] would cause issues. + // can't safeguard this because Queue doesn't have .Last access. + public static void Insert( + Queue> history, + int historyLimit, + double timestamp, + T capture) + where T : Capture + { + // make space according to history limit. + // do this before inserting, to avoid resizing past capacity. + if (history.Count >= historyLimit) + history.Dequeue(); + + // insert + history.Enqueue(new KeyValuePair(timestamp, capture)); + } + + // get the two snapshots closest to a given timestamp. + // those can be used to interpolate the exact snapshot at that time. + // if timestamp is newer than the newest history entry, then we extrapolate. + // 't' will be between 1 and 2, before is second last, after is last. + // callers should Lerp(before, after, t=1.5) to extrapolate the hit. + // see comments below for extrapolation. + public static bool Sample( + Queue> history, + double timestamp, // current server time + double interval, // capture interval + out T before, + out T after, + out double t) // interpolation factor + where T : Capture + { + before = default; + after = default; + t = 0; + + // can't sample an empty history + // interpolation needs at least one entry. + // extrapolation needs at least two entries. + // can't Lerp(A, A, 1.5). dist(A, A) * 1.5 is always 0. + if(history.Count < 2) { + return false; + } + + // older than oldest + if (timestamp < history.Peek().Key) { + return false; + } + + // iterate through the history + // TODO faster version: guess start index by how many 'intervals' we are behind. + // search around that area. + // should be O(1) most of the time, unless sampling was off. + KeyValuePair prev = new KeyValuePair(); + KeyValuePair prevPrev = new KeyValuePair(); + foreach(KeyValuePair entry in history) { + // exact match? + if (timestamp == entry.Key) { + before = entry.Value; + after = entry.Value; + t = Mathd.InverseLerp(before.timestamp, after.timestamp, timestamp); + return true; + } + + // did we check beyond timestamp? then return the previous two. + if (entry.Key > timestamp) { + before = prev.Value; + after = entry.Value; + t = Mathd.InverseLerp(before.timestamp, after.timestamp, timestamp); + return true; + } + + // remember the last two for extrapolation. + // Queue doesn't have access to .Last. + prevPrev = prev; + prev = entry; + } + + // newer than newest: extrapolate up to one interval. + // let's say we capture every 100 ms: + // 100, 200, 300, 400 + // and the server is at 499 + // if a client sends CmdFire at time 480, then there's no history entry. + // => adding the current entry every time would be too expensive. + // worst case we would capture at 401, 402, 403, 404, ... 100 times + // => not extrapolating isn't great. low latency clients would be + // punished by missing their targets since no entry at 'time' was found. + // => extrapolation is the best solution. make sure this works as + // expected and within limits. + if (prev.Key < timestamp && timestamp <= prev.Key + interval) { + // return the last two valid snapshots. + // can't just return (after, after) because we can't extrapolate + // if their distance is 0. + before = prevPrev.Value; + after = prev.Value; + + // InverseLerp will give [after, after+interval]. + // but we return [before, after, t]. + // so add +1 for the distance from before->after + t = 1 + Mathd.InverseLerp(after.timestamp, after.timestamp + interval, timestamp); + return true; + } + + return false; + } + + // never trust the client. + // we estimate when a message was sent. + // don't trust the client to tell us the time. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation + // => lag compensation demo estimation is off by only ~6ms + public static double EstimateTime(double serverTime, double rtt, double bufferTime) + { + // packet latency is one trip from client to server, so rtt / 2 + // client view interpolation is the snapshot interpolation buffer time + double latency = rtt / 2; + return serverTime - latency - bufferTime; + } + + // convenience function to draw all history gizmos. + // this should be called from OnDrawGizmos. + public static void DrawGizmos(Queue> history) + where T : Capture + { + foreach (KeyValuePair entry in history) + entry.Value.DrawGizmo(); + } + } +} diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta new file mode 100644 index 0000000..c697593 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensation.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ad53cc7d12144d0ba3a8b0a4515e5d17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LagCompensation/LagCompensation.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs new file mode 100644 index 0000000..a7ec944 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs @@ -0,0 +1,19 @@ +// snapshot interpolation settings struct. +// can easily be exposed in Unity inspectors. +using System; +using UnityEngine; + +namespace Mirror +{ + // class so we can define defaults easily + [Serializable] + public class LagCompensationSettings + { + [Header("Buffering")] + [Tooltip("Keep this many past snapshots in the buffer. The larger this is, the further we can rewind into the past.\nMaximum rewind time := historyAmount * captureInterval")] + public int historyLimit = 6; + + [Tooltip("Capture state every 'captureInterval' seconds. Larger values will space out the captures more, which gives a longer history but with possible gaps inbetween.\nSmaller values will have fewer gaps, with shorter history.")] + public float captureInterval = 0.100f; // 100 ms + } +} diff --git a/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta new file mode 100644 index 0000000..d57904c --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: fa80bec245f94bf8a28ec78777992a1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LagCompensation/LagCompensationSettings.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs new file mode 100644 index 0000000..b1b4874 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs @@ -0,0 +1,73 @@ +// Unity's Bounds struct is represented as (center, extents). +// HistoryBounds make heavy use of .Encapsulate(), which has to convert +// Unity's (center, extents) to (min, max) every time, and then convert back. +// +// It's faster to use a (min, max) representation directly instead. +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public struct MinMaxBounds: IEquatable + { + public Vector3 min; + public Vector3 max; + + // encapsulate a single point + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Encapsulate(Vector3 point) + { + min = Vector3.Min(this.min, point); + max = Vector3.Max(this.max, point); + } + + // encapsulate another bounds + public void Encapsulate(MinMaxBounds bounds) + { + Encapsulate(bounds.min); + Encapsulate(bounds.max); + } + + // convenience comparison with Unity's bounds, for unit tests etc. + public static bool operator ==(MinMaxBounds lhs, Bounds rhs) => + lhs.min == rhs.min && + lhs.max == rhs.max; + + public static bool operator !=(MinMaxBounds lhs, Bounds rhs) => + !(lhs == rhs); + + public override bool Equals(object obj) => + obj is MinMaxBounds other && + min == other.min && + max == other.max; + + public bool Equals(MinMaxBounds other) => + min.Equals(other.min) && max.Equals(other.max); + + public bool Equals(Bounds other) => + min.Equals(other.min) && max.Equals(other.max); + +#if UNITY_2021_3_OR_NEWER + // Unity 2019/2020 don't have HashCode.Combine yet. + // this is only to avoid reflection. without defining, it works too. + // default generated by rider + public override int GetHashCode() => HashCode.Combine(min, max); +#else + public override int GetHashCode() + { + // return HashCode.Combine(min, max); without using .Combine for older Unity versions + unchecked + { + int hash = 17; + hash = hash * 23 + min.GetHashCode(); + hash = hash * 23 + max.GetHashCode(); + return hash; + } + } +#endif + + // tostring + public override string ToString() => $"({min}, {max})"; + } +} diff --git a/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta new file mode 100644 index 0000000..04b5ed9 --- /dev/null +++ b/Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4372b1e1a1cc4c669cc7bf0925f59d29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LagCompensation/MinMaxBounds.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LocalConnectionToClient.cs b/Assets/Mirror/Core/LocalConnectionToClient.cs new file mode 100644 index 0000000..3ceba29 --- /dev/null +++ b/Assets/Mirror/Core/LocalConnectionToClient.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; + +namespace Mirror +{ + // a server's connection TO a LocalClient. + // sending messages on this connection causes the client's handler function to be invoked directly + public class LocalConnectionToClient : NetworkConnectionToClient + { + internal LocalConnectionToServer connectionToServer; + + // packet queue + internal readonly Queue queue = new Queue(); + + public LocalConnectionToClient() : base(LocalConnectionId) {} + + internal override void Send(ArraySegment segment, int channelId = Channels.Reliable) + { + // instead of invoking it directly, we enqueue and process next update. + // this way we can simulate a similar call flow as with remote clients. + // the closer we get to simulating host as remote, the better! + // both directions do this, so [Command] and [Rpc] behave the same way. + + //Debug.Log($"Enqueue {BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}"); + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.WriteBytes(segment.Array, segment.Offset, segment.Count); + connectionToServer.queue.Enqueue(writer); + } + + // true because local connections never timeout + internal override bool IsAlive(float timeout) => true; + + // don't ping host client in host mode + protected override void UpdatePing() {} + + internal override void Update() + { + base.Update(); + + // process internal messages so they are applied at the correct time + while (queue.Count > 0) + { + // call receive on queued writer's content, return to pool + NetworkWriterPooled writer = queue.Dequeue(); + ArraySegment message = writer.ToArraySegment(); + + // OnTransportData assumes a proper batch with timestamp etc. + // let's make a proper batch and pass it to OnTransportData. + Batcher batcher = GetBatchForChannelId(Channels.Reliable); + batcher.AddMessage(message, NetworkTime.localTime); + + using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get()) + { + // make a batch with our local time (double precision) + if (batcher.GetBatch(batchWriter)) + { + NetworkServer.OnTransportData(connectionId, batchWriter.ToArraySegment(), Channels.Reliable); + } + } + + NetworkWriterPool.Return(writer); + } + } + + internal void DisconnectInternal() + { + // set not ready and handle clientscene disconnect in any case + // (might be client or host mode here) + isReady = false; + RemoveFromObservingsObservers(); + } + + /// Disconnects this connection. + public override void Disconnect() + { + DisconnectInternal(); + connectionToServer.DisconnectInternal(); + } + } +} diff --git a/Assets/Mirror/Core/LocalConnectionToClient.cs.meta b/Assets/Mirror/Core/LocalConnectionToClient.cs.meta new file mode 100644 index 0000000..e910e0d --- /dev/null +++ b/Assets/Mirror/Core/LocalConnectionToClient.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a88758df7db2043d6a9d926e0b6d4191 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LocalConnectionToClient.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/LocalConnectionToServer.cs b/Assets/Mirror/Core/LocalConnectionToServer.cs new file mode 100644 index 0000000..15669c7 --- /dev/null +++ b/Assets/Mirror/Core/LocalConnectionToServer.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // a localClient's connection TO a server. + // send messages on this connection causes the server's handler function to be invoked directly. + public class LocalConnectionToServer : NetworkConnectionToServer + { + internal LocalConnectionToClient connectionToClient; + + // packet queue + internal readonly Queue queue = new Queue(); + + // see caller for comments on why we need this + bool connectedEventPending; + bool disconnectedEventPending; + internal void QueueConnectedEvent() => connectedEventPending = true; + internal void QueueDisconnectedEvent() => disconnectedEventPending = true; + + // Send stage two: serialized NetworkMessage as ArraySegment + internal override void Send(ArraySegment segment, int channelId = Channels.Reliable) + { + if (segment.Count == 0) + { + Debug.LogError("LocalConnection.SendBytes cannot send zero bytes"); + return; + } + + // instead of invoking it directly, we enqueue and process next update. + // this way we can simulate a similar call flow as with remote clients. + // the closer we get to simulating host as remote, the better! + // both directions do this, so [Command] and [Rpc] behave the same way. + + //Debug.Log($"Enqueue {BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}"); + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.WriteBytes(segment.Array, segment.Offset, segment.Count); + connectionToClient.queue.Enqueue(writer); + } + + internal override void Update() + { + base.Update(); + + // should we still process a connected event? + if (connectedEventPending) + { + connectedEventPending = false; + NetworkClient.OnConnectedEvent?.Invoke(); + } + + // process internal messages so they are applied at the correct time + while (queue.Count > 0) + { + // call receive on queued writer's content, return to pool + NetworkWriterPooled writer = queue.Dequeue(); + ArraySegment message = writer.ToArraySegment(); + + // OnTransportData assumes a proper batch with timestamp etc. + // let's make a proper batch and pass it to OnTransportData. + Batcher batcher = GetBatchForChannelId(Channels.Reliable); + batcher.AddMessage(message, NetworkTime.localTime); + + using (NetworkWriterPooled batchWriter = NetworkWriterPool.Get()) + { + // make a batch with our local time (double precision) + if (batcher.GetBatch(batchWriter)) + { + NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable); + } + } + + NetworkWriterPool.Return(writer); + } + + // should we still process a disconnected event? + if (disconnectedEventPending) + { + disconnectedEventPending = false; + NetworkClient.OnDisconnectedEvent?.Invoke(); + } + } + + /// Disconnects this connection. + internal void DisconnectInternal() + { + // set not ready and handle clientscene disconnect in any case + // (might be client or host mode here) + // TODO remove redundant state. have one source of truth for .ready! + isReady = false; + NetworkClient.ready = false; + } + + /// Disconnects this connection. + public override void Disconnect() + { + connectionToClient.DisconnectInternal(); + DisconnectInternal(); + + // simulate what a true remote connection would do: + // first, the server should remove it: + // TODO should probably be in connectionToClient.DisconnectInternal + // because that's the NetworkServer's connection! + NetworkServer.RemoveLocalConnection(); + + // then call OnTransportDisconnected for proper disconnect handling, + // callbacks & cleanups. + // => otherwise OnClientDisconnected() is never called! + // => see NetworkClientTests.DisconnectCallsOnClientDisconnect_HostMode() + NetworkClient.OnTransportDisconnected(); + } + + // true because local connections never timeout + internal override bool IsAlive(float timeout) => true; + } +} diff --git a/Assets/Mirror/Core/LocalConnectionToServer.cs.meta b/Assets/Mirror/Core/LocalConnectionToServer.cs.meta new file mode 100644 index 0000000..4a1ee42 --- /dev/null +++ b/Assets/Mirror/Core/LocalConnectionToServer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cdfff390c3504158a269e8b8662e2a40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/LocalConnectionToServer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Messages.cs b/Assets/Mirror/Core/Messages.cs new file mode 100644 index 0000000..899b0ea --- /dev/null +++ b/Assets/Mirror/Core/Messages.cs @@ -0,0 +1,186 @@ +using System; +using UnityEngine; + +namespace Mirror +{ + // need to send time every sendInterval. + // batching automatically includes remoteTimestamp. + // all we need to do is ensure that an empty message is sent. + // and react to it. + // => we don't want to insert a snapshot on every batch. + // => do it exactly every sendInterval on every TimeSnapshotMessage. + public struct TimeSnapshotMessage : NetworkMessage {} + + public struct ReadyMessage : NetworkMessage {} + + public struct NotReadyMessage : NetworkMessage {} + + public struct AddPlayerMessage : NetworkMessage {} + + public struct SceneMessage : NetworkMessage + { + public string sceneName; + // Normal = 0, LoadAdditive = 1, UnloadAdditive = 2 + public SceneOperation sceneOperation; + public bool customHandling; + } + + public enum SceneOperation : byte + { + Normal, + LoadAdditive, + UnloadAdditive + } + + public struct CommandMessage : NetworkMessage + { + public uint netId; + public byte componentIndex; + public ushort functionHash; + // the parameters for the Cmd function + // -> ArraySegment to avoid unnecessary allocations + public ArraySegment payload; + } + + public struct RpcMessage : NetworkMessage + { + public uint netId; + public byte componentIndex; + public ushort functionHash; + // the parameters for the Cmd function + // -> ArraySegment to avoid unnecessary allocations + public ArraySegment payload; + } + + [Flags] public enum SpawnFlags : byte + { + None = 0, + isOwner = 1 << 0, + isLocalPlayer = 1 << 1 + } + + public struct SpawnMessage : NetworkMessage + { + // netId of new or existing object + public uint netId; + // isOwner and isLocalPlayer are merged into one byte via bitwise op + public SpawnFlags spawnFlags; + public ulong sceneId; + // If sceneId != 0 then it is used instead of assetId + public uint assetId; + // Local position + public Vector3 position; + // Local rotation + public Quaternion rotation; + // Local scale + public Vector3 scale; + // serialized component data + // ArraySegment to avoid unnecessary allocations + public ArraySegment payload; + + // Backwards compatibility after implementing spawnFlags + public bool isOwner + { + get => spawnFlags.HasFlag(SpawnFlags.isOwner); + set => spawnFlags = + value + ? spawnFlags | SpawnFlags.isOwner + : spawnFlags & ~SpawnFlags.isOwner; + } + + // Backwards compatibility after implementing spawnFlags + public bool isLocalPlayer + { + get => spawnFlags.HasFlag(SpawnFlags.isLocalPlayer); + set => spawnFlags = + value + ? spawnFlags | SpawnFlags.isLocalPlayer + : spawnFlags & ~SpawnFlags.isLocalPlayer; + } + } + + public struct ChangeOwnerMessage : NetworkMessage + { + public uint netId; + // isOwner and isLocalPlayer are merged into one byte via bitwise op + public SpawnFlags spawnFlags; + + // Backwards compatibility after implementing spawnFlags + public bool isOwner + { + get => spawnFlags.HasFlag(SpawnFlags.isOwner); + set => spawnFlags = + value + ? spawnFlags | SpawnFlags.isOwner + : spawnFlags & ~SpawnFlags.isOwner; + } + + // Backwards compatibility after implementing spawnFlags + public bool isLocalPlayer + { + get => spawnFlags.HasFlag(SpawnFlags.isLocalPlayer); + set => spawnFlags = + value + ? spawnFlags | SpawnFlags.isLocalPlayer + : spawnFlags & ~SpawnFlags.isLocalPlayer; + } + } + + public struct ObjectSpawnStartedMessage : NetworkMessage {} + + public struct ObjectSpawnFinishedMessage : NetworkMessage {} + + public struct ObjectDestroyMessage : NetworkMessage + { + public uint netId; + } + + public struct ObjectHideMessage : NetworkMessage + { + public uint netId; + } + + public struct EntityStateMessage : NetworkMessage + { + public uint netId; + // the serialized component data + // -> ArraySegment to avoid unnecessary allocations + public ArraySegment payload; + } + + // whoever wants to measure rtt, sends this to the other end. + public struct NetworkPingMessage : NetworkMessage + { + // local time is used to calculate round trip time, + // and to calculate the predicted time offset. + public double localTime; + + // predicted time is sent to compare the final error, for debugging only + public double predictedTimeAdjusted; + + public NetworkPingMessage(double localTime, double predictedTimeAdjusted) + { + this.localTime = localTime; + this.predictedTimeAdjusted = predictedTimeAdjusted; + } + } + + // the other end responds with this message. + // we can use this to calculate rtt. + public struct NetworkPongMessage : NetworkMessage + { + // local time is used to calculate round trip time. + public double localTime; + + // predicted error is used to adjust the predicted timeline. + public double predictionErrorUnadjusted; + public double predictionErrorAdjusted; // for debug purposes + + public NetworkPongMessage(double localTime, double predictionErrorUnadjusted, double predictionErrorAdjusted) + { + this.localTime = localTime; + this.predictionErrorUnadjusted = predictionErrorUnadjusted; + this.predictionErrorAdjusted = predictionErrorAdjusted; + } + } +} diff --git a/Assets/Mirror/Core/Messages.cs.meta b/Assets/Mirror/Core/Messages.cs.meta new file mode 100644 index 0000000..3411dc8 --- /dev/null +++ b/Assets/Mirror/Core/Messages.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 938f6f28a6c5b48a0bbd7782342d763b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Messages.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Mirror.asmdef b/Assets/Mirror/Core/Mirror.asmdef new file mode 100644 index 0000000..2fa8d95 --- /dev/null +++ b/Assets/Mirror/Core/Mirror.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Mirror", + "rootNamespace": "", + "references": [ + "GUID:325984b52e4128546bc7558552f8b1d2" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Core/Mirror.asmdef.meta b/Assets/Mirror/Core/Mirror.asmdef.meta new file mode 100644 index 0000000..69f6cee --- /dev/null +++ b/Assets/Mirror/Core/Mirror.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 30817c1a0e6d646d99c048fc403f5979 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Mirror.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkAuthenticator.cs b/Assets/Mirror/Core/NetworkAuthenticator.cs new file mode 100644 index 0000000..aa1e7f7 --- /dev/null +++ b/Assets/Mirror/Core/NetworkAuthenticator.cs @@ -0,0 +1,84 @@ +using System; +using UnityEngine; +using UnityEngine.Events; + +namespace Mirror +{ + [Serializable] public class UnityEventNetworkConnection : UnityEvent {} + + /// Base class for implementing component-based authentication during the Connect phase + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-authenticators")] + public abstract class NetworkAuthenticator : MonoBehaviour + { + /// Notify subscribers on the server when a client is authenticated + [Header("Event Listeners (optional)")] + [Tooltip("Mirror has an internal subscriber to this event. You can add your own here.")] + public UnityEventNetworkConnection OnServerAuthenticated = new UnityEventNetworkConnection(); + + /// Notify subscribers on the client when the client is authenticated + [Tooltip("Mirror has an internal subscriber to this event. You can add your own here.")] + public UnityEvent OnClientAuthenticated = new UnityEvent(); + + /// Called when server starts, used to register message handlers if needed. + public virtual void OnStartServer() {} + + /// Called when server stops, used to unregister message handlers if needed. + public virtual void OnStopServer() {} + + /// Called on server from OnServerConnectInternal when a client needs to authenticate + public virtual void OnServerAuthenticate(NetworkConnectionToClient conn) {} + + protected void ServerAccept(NetworkConnectionToClient conn) + { + OnServerAuthenticated.Invoke(conn); + } + + protected void ServerReject(NetworkConnectionToClient conn) + { + conn.Disconnect(); + } + + /// Called when client starts, used to register message handlers if needed. + public virtual void OnStartClient() {} + + /// Called when client stops, used to unregister message handlers if needed. + public virtual void OnStopClient() {} + + /// Called on client from OnClientConnectInternal when a client needs to authenticate + public virtual void OnClientAuthenticate() {} + + protected void ClientAccept() + { + OnClientAuthenticated.Invoke(); + } + + protected void ClientReject() + { + // Set this on the client for local reference + NetworkClient.connection.isAuthenticated = false; + + // disconnect the client + NetworkClient.connection.Disconnect(); + } + + // Reset() instead of OnValidate(): + // Any NetworkAuthenticator assigns itself to the NetworkManager, this is fine on first adding it, + // but if someone intentionally sets Authenticator to null on the NetworkManager again then the + // Authenticator will reassign itself if a value in the inspector is changed. + // My change switches OnValidate to Reset since Reset is only called when the component is first + // added (or reset is pressed). + void Reset() + { +#if UNITY_EDITOR + // automatically assign authenticator field if we add this to NetworkManager + NetworkManager manager = GetComponent(); + if (manager != null && manager.authenticator == null) + { + // undo has to be called before the change happens + UnityEditor.Undo.RecordObject(manager, "Assigned NetworkManager authenticator"); + manager.authenticator = this; + } +#endif + } + } +} diff --git a/Assets/Mirror/Core/NetworkAuthenticator.cs.meta b/Assets/Mirror/Core/NetworkAuthenticator.cs.meta new file mode 100644 index 0000000..be59e4a --- /dev/null +++ b/Assets/Mirror/Core/NetworkAuthenticator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 407fc95d4a8257f448799f26cdde0c2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkAuthenticator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkBehaviour.cs b/Assets/Mirror/Core/NetworkBehaviour.cs new file mode 100644 index 0000000..f887f47 --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviour.cs @@ -0,0 +1,1386 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + // SyncMode decides if a component is synced to all observers, or only owner + public enum SyncMode { Observers, Owner } + + // SyncDirection decides if a component is synced from: + // * server to all clients + // * owner client, to server, to all other clients + // + // naming: 'ClientToServer' etc. instead of 'ClientAuthority', because + // that wouldn't be accurate. server's OnDeserialize can still validate + // client data before applying. it's really about direction, not authority. + public enum SyncDirection { ServerToClient, ClientToServer } + + /// Base class for networked components. + // [RequireComponent(typeof(NetworkIdentity))] disabled to allow child NetworkBehaviours + [AddComponentMenu("")] + [HelpURL("https://mirror-networking.gitbook.io/docs/guides/networkbehaviour")] + public abstract class NetworkBehaviour : MonoBehaviour + { + /// Sync direction for OnSerialize. ServerToClient by default. ClientToServer for client authority. + [Tooltip("Server Authority calls OnSerialize on the server and syncs it to clients.\n\nClient Authority calls OnSerialize on the owning client, syncs it to server, which then broadcasts it to all other clients.\n\nUse server authority for cheat safety.")] + [HideInInspector] public SyncDirection syncDirection = SyncDirection.ServerToClient; + + /// sync mode for OnSerialize + // hidden because NetworkBehaviourInspector shows it only if has OnSerialize. + [Tooltip("By default synced data is sent from the server to all Observers of the object.\nChange this to Owner to only have the server update the client that has ownership authority for this object")] + [HideInInspector] public SyncMode syncMode = SyncMode.Observers; + + /// sync interval for OnSerialize (in seconds) + // hidden because NetworkBehaviourInspector shows it only if has OnSerialize. + // [0,2] should be enough. anything >2s is too laggy anyway. + // + // NetworkServer & NetworkClient broadcast() are behind a sendInterval timer now. + // it makes sense to keep every component's syncInterval setting at '0' by default. + // otherwise, the overlapping timers could introduce unexpected latency. + // careful: default of '0.1' may + [Tooltip("Time in seconds until next change is synchronized to the client. '0' means send immediately if changed. '0.5' means only send changes every 500ms.\n(This is for state synchronization like SyncVars, SyncLists, OnSerialize. Not for Cmds, Rpcs, etc.)")] + [Range(0, 2)] + [HideInInspector] public float syncInterval = 0; + internal double lastSyncTime; + + /// True if this object is on the server and has been spawned. + // This is different from NetworkServer.active, which is true if the + // server itself is active rather than this object being active. + public bool isServer => netIdentity.isServer; + + /// True if this object is on the client and has been spawned by the server. + public bool isClient => netIdentity.isClient; + + /// True if this object is the the client's own local player. + public bool isLocalPlayer => netIdentity.isLocalPlayer; + + /// True if this object is on the server-only, not host. + public bool isServerOnly => netIdentity.isServerOnly; + + /// True if this object is on the client-only, not host. + public bool isClientOnly => netIdentity.isClientOnly; + + /// isOwned is true on the client if this NetworkIdentity is one of the .owned entities of our connection on the server. + // for example: main player & pets are owned. monsters & npcs aren't. + public bool isOwned => netIdentity.isOwned; + + /// authority is true if we are allowed to modify this component's state. On server, it's true if SyncDirection is ServerToClient. On client, it's true if SyncDirection is ClientToServer and(!) if this object is owned by the client. + // on the client: if Client->Server SyncDirection and owned + // on the server: if Server->Client SyncDirection + // on the host: if Server->Client SyncDirection (= server owns it), or if Client->Server and owned (=host client owns it) + // in host mode: always true because either server or client always has authority, and host is both. + // + // for example, NetworkTransform: + // client may modify position if ClientAuthority mode and owned + // server may modify position only if server authority + // + // note that in original Mirror, hasAuthority only meant 'isOwned'. + // there was no syncDirection to check. + // + // also note that this is a per-NetworkBehaviour flag. + // another component may not be client authoritative, etc. + public bool authority + { + get + { + // host mode needs to be checked explicitly + if (isClient && isServer) return syncDirection == SyncDirection.ServerToClient || isOwned; + + // client-only + if (isClient) return syncDirection == SyncDirection.ClientToServer && isOwned; + + // server-only + return syncDirection == SyncDirection.ServerToClient; + } + } + + /// The unique network Id of this object (unique at runtime). + public uint netId => netIdentity.netId; + + /// Client's network connection to the server. This is only valid for player objects on the client. + // TODO change to NetworkConnectionToServer, but might cause some breaking + public NetworkConnection connectionToServer => netIdentity.connectionToServer; + + /// Server's network connection to the client. This is only valid for player objects on the server. + public NetworkConnectionToClient connectionToClient => netIdentity.connectionToClient; + + // SyncLists, SyncSets, etc. + protected readonly List syncObjects = new List(); + + // NetworkBehaviourInspector needs to know if we have SyncObjects + internal bool HasSyncObjects() => syncObjects.Count > 0; + + // NetworkIdentity based values set from NetworkIdentity.Awake(), + // which is way more simple and way faster than trying to figure out + // component index from in here by searching all NetworkComponents. + + /// Returns the NetworkIdentity of this object + public NetworkIdentity netIdentity { get; internal set; } + + /// Returns the index of the component on this object + public byte ComponentIndex { get; internal set; } + + // to avoid fully serializing entities every time, we have two options: + // * run a delta compression algorithm + // -> for fixed size types this is as easy as varint(b-a) for all + // -> for dynamically sized types like strings this is not easy. + // algorithms need to detect inserts/deletions, i.e. Myers Diff. + // those are very cpu intensive and barely fast enough for large + // scale multiplayer games (in Unity) + // * or we use dirty bits as meta data about which fields have changed + // -> spares us from running delta algorithms + // -> still supports dynamically sized types + // + // 64 bit mask, tracking up to 64 SyncVars. + // protected since NB child classes read this field in the weaver generated SerializeSyncVars method + protected ulong syncVarDirtyBits; + // 64 bit mask, tracking up to 64 sync collections. + // internal for tests, field for faster access (instead of property) + // TODO 64 SyncLists are too much. consider smaller mask later. + internal ulong syncObjectDirtyBits; + + // Weaver replaces '[SyncVar] int health' with 'Networkhealth' property. + // setter calls the hook if value changed. + // if we then modify the [SyncVar] from inside the setter, + // the setter would call the hook and we deadlock. + // hook guard prevents that. + ulong syncVarHookGuard; + + protected virtual void OnValidate() + { + // Skip if Editor is in Play mode + if (Application.isPlaying) return; + + // we now allow child NetworkBehaviours. + // we can not [RequireComponent(typeof(NetworkIdentity))] anymore. + // instead, we need to ensure a NetworkIdentity is somewhere in the + // parents. + // only run this in Editor. don't add more runtime overhead. + + // GetComponentInParent(includeInactive) is needed because Prefabs are not + // considered active, so this check requires to scan inactive. +#if UNITY_2021_3_OR_NEWER // 2021 has GetComponentInParent(bool includeInactive = false) + if (GetComponent() == null && + GetComponentInParent(true) == null) + { + Debug.LogError($"{GetType()} on {name} requires a NetworkIdentity. Please add a NetworkIdentity component to {name} or its parents.", this); + } +#elif UNITY_2020_3_OR_NEWER // 2020 only has GetComponentsInParent(bool includeInactive = false), we can use this too + NetworkIdentity[] parentsIds = GetComponentsInParent(true); + int parentIdsCount = parentsIds != null ? parentsIds.Length : 0; + if (GetComponent() == null && parentIdsCount == 0) + { + Debug.LogError($"{GetType()} on {name} requires a NetworkIdentity. Please add a NetworkIdentity component to {name} or its parents.", this); + } +#endif + } + + // USED BY WEAVER to set syncvars in host mode without deadlocking + protected bool GetSyncVarHookGuard(ulong dirtyBit) => + (syncVarHookGuard & dirtyBit) != 0UL; + + // USED BY WEAVER to set syncvars in host mode without deadlocking + protected void SetSyncVarHookGuard(ulong dirtyBit, bool value) + { + // set the bit + if (value) + syncVarHookGuard |= dirtyBit; + // clear the bit + else + syncVarHookGuard &= ~dirtyBit; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void SetSyncObjectDirtyBit(ulong dirtyBit) + { + syncObjectDirtyBits |= dirtyBit; + } + + /// Set as dirty so that it's synced to clients again. + // these are masks, not bit numbers, ie. 110011b not '2' for 2nd bit. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetSyncVarDirtyBit(ulong dirtyBit) + { + syncVarDirtyBits |= dirtyBit; + } + + /// Set as dirty to trigger OnSerialize & send. Dirty bits are cleared after the send. + // previously one had to use SetSyncVarDirtyBit(1), which is confusing. + // simply reuse SetSyncVarDirtyBit for now. + // instead of adding another field. + // syncVarDirtyBits does trigger OnSerialize as well. + // + // it's important to set _all_ bits as dirty. + // for example, server needs to broadcast ClientToServer components. + // if we only set the first bit, only that SyncVar would be broadcast. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetDirty() => SetSyncVarDirtyBit(ulong.MaxValue); + + // true if syncInterval elapsed and any SyncVar or SyncObject is dirty + // OR both bitmasks. != 0 if either was dirty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsDirty() => + // check bits first. this is basically free. + (syncVarDirtyBits | syncObjectDirtyBits) != 0UL && + // only check time if bits were dirty. this is more expensive. + NetworkTime.localTime - lastSyncTime >= syncInterval; + + /// Clears all the dirty bits that were set by SetSyncVarDirtyBit() (formally SetDirtyBits) + // automatically invoked when an update is sent for this object, but can + // be called manually as well. + public void ClearAllDirtyBits() + { + lastSyncTime = NetworkTime.localTime; + syncVarDirtyBits = 0L; + syncObjectDirtyBits = 0L; + + // clear all unsynchronized changes in syncobjects + // (Linq allocates, use for instead) + for (int i = 0; i < syncObjects.Count; ++i) + { + syncObjects[i].ClearChanges(); + } + } + + // this gets called in the constructor by the weaver + // for every SyncObject in the component (e.g. SyncLists). + // We collect all of them and we synchronize them with OnSerialize/OnDeserialize + protected void InitSyncObject(SyncObject syncObject) + { + if (syncObject == null) + { + Debug.LogError("Uninitialized SyncObject. Manually call the constructor on your SyncList, SyncSet, SyncDictionary or SyncField"); + return; + } + + // add it, remember the index in list (if Count=0, index=0 etc.) + int index = syncObjects.Count; + syncObjects.Add(syncObject); + + // OnDirty needs to set nth bit in our dirty mask + ulong nthBit = 1UL << index; + syncObject.OnDirty = () => SetSyncObjectDirtyBit(nthBit); + + // who is allowed to modify SyncList/SyncSet/etc.: + // on client: only if owned ClientToserver + // on server: only if ServerToClient. + // but also for initial state when spawning. + // need to set a lambda because 'isClient' isn't available in + // InitSyncObject yet, which is called from the constructor. + syncObject.IsWritable = () => + { + // carefully check each mode separately to ensure correct results. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3342 + + // normally we would check isServer / isClient here. + // users may add to SyncLists before the object was spawned. + // isServer / isClient would still be false. + // so we need to check NetworkServer/Client.active here instead. + + // host mode: any ServerToClient and any local client owned + if (NetworkServer.active && NetworkClient.active) + return syncDirection == SyncDirection.ServerToClient || isOwned; + + // server only: any ServerToClient + if (NetworkServer.active) + return syncDirection == SyncDirection.ServerToClient; + + // client only: only ClientToServer and owned + if (NetworkClient.active) + { + // spawned: only ClientToServer and owned + if (netId != 0) return syncDirection == SyncDirection.ClientToServer && isOwned; + + // not spawned (character selection previews, etc.): always allow + // fixes https://github.com/MirrorNetworking/Mirror/issues/3343 + return true; + } + + // undefined behaviour should throw to make it very obvious + throw new Exception("InitSyncObject: IsWritable: neither NetworkServer nor NetworkClient are active."); + }; + + // when do we record changes: + // on client: only if owned ClientToServer + // on server: only if we have observers. + // prevents ever growing .changes lists: + // if a monster has no observers but we keep modifing a SyncObject, + // then the changes would never be flushed and keep growing, + // because OnSerialize isn't called without observers. + syncObject.IsRecording = () => + { + // carefully check each mode separately to ensure correct results. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3342 + + // host mode: only if observed + if (isServer && isClient) return netIdentity.observers.Count > 0; + + // server only: only if observed + if (isServer) return netIdentity.observers.Count > 0; + + // client only: only ClientToServer and owned + if (isClient) return syncDirection == SyncDirection.ClientToServer && isOwned; + + // users may add to SyncLists before the object was spawned. + // isServer / isClient would still be false. + // in that case, allow modifying but don't record changes yet. + return false; + }; + } + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + protected void SendCommandInternal(string functionFullName, int functionHashCode, NetworkWriter writer, int channelId, bool requiresAuthority = true) + { + // this was in Weaver before + // NOTE: we could remove this later to allow calling Cmds on Server + // to avoid Wrapper functions. a lot of people requested this. + if (!NetworkClient.active) + { + Debug.LogError($"Command {functionFullName} called on {name} without an active client.", gameObject); + return; + } + + // previously we used NetworkClient.readyConnection. + // now we check .ready separately. + if (!NetworkClient.ready) + { + // Unreliable Cmds from NetworkTransform may be generated, + // or client may have been set NotReady intentionally, so + // only warn if on the reliable channel. + if (channelId == Channels.Reliable) + Debug.LogWarning($"Command {functionFullName} called on {name} while NetworkClient is not ready.\nThis may be ignored if client intentionally set NotReady.", gameObject); + return; + } + + // local players can always send commands, regardless of authority, + // other objects must have authority. + if (!(!requiresAuthority || isLocalPlayer || isOwned)) + { + Debug.LogWarning($"Command {functionFullName} called on {name} without authority.", gameObject); + return; + } + + // IMPORTANT: can't use .connectionToServer here because calling + // a command on other objects is allowed if requireAuthority is + // false. other objects don't have a .connectionToServer. + // => so we always need to use NetworkClient.connection instead. + // => see also: https://github.com/vis2k/Mirror/issues/2629 + if (NetworkClient.connection == null) + { + Debug.LogError($"Command {functionFullName} called on {name} with no client running.", gameObject); + return; + } + + if (netId == 0) + { + Debug.LogWarning($"Command {functionFullName} called on {name} with netId=0. Maybe it wasn't spawned yet?", gameObject); + return; + } + + // construct the message + CommandMessage message = new CommandMessage + { + netId = netId, + componentIndex = ComponentIndex, + // type+func so Inventory.RpcUse != Equipment.RpcUse + functionHash = (ushort)functionHashCode, + // segment to avoid reader allocations + payload = writer.ToArraySegment() + }; + + // IMPORTANT: can't use .connectionToServer here because calling + // a command on other objects is allowed if requireAuthority is + // false. other objects don't have a .connectionToServer. + // => so we always need to use NetworkClient.connection instead. + // => see also: https://github.com/vis2k/Mirror/issues/2629 + // This bypasses the null check in NetworkClient.Send but we have + // a null check above with a detailed error log. + NetworkClient.connection.Send(message, channelId); + } + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + protected void SendRPCInternal(string functionFullName, int functionHashCode, NetworkWriter writer, int channelId, bool includeOwner) + { + // this was in Weaver before + if (!NetworkServer.active) + { + Debug.LogError($"RPC Function {functionFullName} called without an active server.", gameObject); + return; + } + + // This cannot use NetworkServer.active, as that is not specific to this object. + if (!isServer) + { + Debug.LogWarning($"ClientRpc {functionFullName} called on un-spawned object: {name}", gameObject); + return; + } + + // construct the message + RpcMessage message = new RpcMessage + { + netId = netId, + componentIndex = ComponentIndex, + // type+func so Inventory.RpcUse != Equipment.RpcUse + functionHash = (ushort)functionHashCode, + // segment to avoid reader allocations + payload = writer.ToArraySegment() + }; + + // serialize it to each ready observer's connection's rpc buffer. + // send them all at once, instead of sending one message per rpc. + // NetworkServer.SendToReadyObservers(netIdentity, message, includeOwner, channelId); + + // safety check used to be in SendToReadyObservers. keep it for now. + if (netIdentity.observers == null || netIdentity.observers.Count == 0) + return; + + // serialize the message only once + using (NetworkWriterPooled serialized = NetworkWriterPool.Get()) + { + serialized.Write(message); + + // send to every observer. + // batching buffers this automatically. + foreach (NetworkConnectionToClient conn in netIdentity.observers.Values) + { + bool isOwner = conn == netIdentity.connectionToClient; + if ((!isOwner || includeOwner) && conn.isReady) + { + conn.Send(message, channelId); + } + } + } + } + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + protected void SendTargetRPCInternal(NetworkConnection conn, string functionFullName, int functionHashCode, NetworkWriter writer, int channelId) + { + if (!NetworkServer.active) + { + Debug.LogError($"TargetRPC {functionFullName} was called on {name} when server not active.", gameObject); + return; + } + + if (!isServer) + { + Debug.LogWarning($"TargetRpc {functionFullName} called on {name} but that object has not been spawned or has been unspawned.", gameObject); + return; + } + + // connection parameter is optional. assign if null. + if (conn is null) + { + conn = connectionToClient; + } + + // if still null + if (conn is null) + { + Debug.LogError($"TargetRPC {functionFullName} can't be sent because it was given a null connection. Make sure {name} is owned by a connection, or if you pass a connection manually then make sure it's not null. For example, TargetRpcs can be called on Player/Pet which are owned by a connection. However, they can not be called on Monsters/Npcs which don't have an owner connection.", gameObject); + return; + } + + // TODO change conn type to NetworkConnectionToClient to begin with. + if (!(conn is NetworkConnectionToClient connToClient)) + { + Debug.LogError($"TargetRPC {functionFullName} called on {name} requires a NetworkConnectionToClient but was given {conn.GetType().Name}", gameObject); + return; + } + + // construct the message + RpcMessage message = new RpcMessage + { + netId = netId, + componentIndex = ComponentIndex, + // type+func so Inventory.RpcUse != Equipment.RpcUse + functionHash = (ushort)functionHashCode, + // segment to avoid reader allocations + payload = writer.ToArraySegment() + }; + + // send it to the connection. + // batching buffers this automatically. + conn.Send(message, channelId); + } + + // move the [SyncVar] generated property's .set into C# to avoid much IL + // + // public int health = 42; + // + // public int Networkhealth + // { + // get + // { + // return health; + // } + // [param: In] + // set + // { + // if (!NetworkBehaviour.SyncVarEqual(value, ref health)) + // { + // int oldValue = health; + // SetSyncVar(value, ref health, 1uL); + // if (NetworkServer.activeHost && !GetSyncVarHookGuard(1uL)) + // { + // SetSyncVarHookGuard(1uL, value: true); + // OnChanged(oldValue, value); + // SetSyncVarHookGuard(1uL, value: false); + // } + // } + // } + // } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GeneratedSyncVarSetter(T value, ref T field, ulong dirtyBit, Action OnChanged) + { + if (!SyncVarEqual(value, ref field)) + { + T oldValue = field; + SetSyncVar(value, ref field, dirtyBit); + + // call hook (if any) + if (OnChanged != null) + { + // in host mode, setting a SyncVar calls the hook directly. + // in client-only mode, OnDeserialize would call it. + // we use hook guard to protect against deadlock where hook + // changes syncvar, calling hook again. + if (NetworkServer.activeHost && !GetSyncVarHookGuard(dirtyBit)) + { + SetSyncVarHookGuard(dirtyBit, true); + OnChanged(oldValue, value); + SetSyncVarHookGuard(dirtyBit, false); + } + } + } + } + + // GameObject needs custom handling for persistence via netId. + // has one extra parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GeneratedSyncVarSetter_GameObject(GameObject value, ref GameObject field, ulong dirtyBit, Action OnChanged, ref uint netIdField) + { + if (!SyncVarGameObjectEqual(value, netIdField)) + { + GameObject oldValue = field; + SetSyncVarGameObject(value, ref field, dirtyBit, ref netIdField); + + // call hook (if any) + if (OnChanged != null) + { + // in host mode, setting a SyncVar calls the hook directly. + // in client-only mode, OnDeserialize would call it. + // we use hook guard to protect against deadlock where hook + // changes syncvar, calling hook again. + if (NetworkServer.activeHost && !GetSyncVarHookGuard(dirtyBit)) + { + SetSyncVarHookGuard(dirtyBit, true); + OnChanged(oldValue, value); + SetSyncVarHookGuard(dirtyBit, false); + } + } + } + } + + // NetworkIdentity needs custom handling for persistence via netId. + // has one extra parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GeneratedSyncVarSetter_NetworkIdentity(NetworkIdentity value, ref NetworkIdentity field, ulong dirtyBit, Action OnChanged, ref uint netIdField) + { + if (!SyncVarNetworkIdentityEqual(value, netIdField)) + { + NetworkIdentity oldValue = field; + SetSyncVarNetworkIdentity(value, ref field, dirtyBit, ref netIdField); + + // call hook (if any) + if (OnChanged != null) + { + // in host mode, setting a SyncVar calls the hook directly. + // in client-only mode, OnDeserialize would call it. + // we use hook guard to protect against deadlock where hook + // changes syncvar, calling hook again. + if (NetworkServer.activeHost && !GetSyncVarHookGuard(dirtyBit)) + { + SetSyncVarHookGuard(dirtyBit, true); + OnChanged(oldValue, value); + SetSyncVarHookGuard(dirtyBit, false); + } + } + } + } + + // NetworkBehaviour needs custom handling for persistence via netId. + // has one extra parameter. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GeneratedSyncVarSetter_NetworkBehaviour(T value, ref T field, ulong dirtyBit, Action OnChanged, ref NetworkBehaviourSyncVar netIdField) + where T : NetworkBehaviour + { + if (!SyncVarNetworkBehaviourEqual(value, netIdField)) + { + T oldValue = field; + SetSyncVarNetworkBehaviour(value, ref field, dirtyBit, ref netIdField); + + // call hook (if any) + if (OnChanged != null) + { + // in host mode, setting a SyncVar calls the hook directly. + // in client-only mode, OnDeserialize would call it. + // we use hook guard to protect against deadlock where hook + // changes syncvar, calling hook again. + if (NetworkServer.activeHost && !GetSyncVarHookGuard(dirtyBit)) + { + SetSyncVarHookGuard(dirtyBit, true); + OnChanged(oldValue, value); + SetSyncVarHookGuard(dirtyBit, false); + } + } + } + } + + // helper function for [SyncVar] GameObjects. + // needs to be public so that tests & NetworkBehaviours from other + // assemblies both find it + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool SyncVarGameObjectEqual(GameObject newGameObject, uint netIdField) + { + uint newNetId = 0; + if (newGameObject != null) + { + if (newGameObject.TryGetComponent(out NetworkIdentity identity)) + { + newNetId = identity.netId; + if (newNetId == 0) + { + Debug.LogWarning($"SetSyncVarGameObject GameObject {newGameObject} has a zero netId. Maybe it is not spawned yet?"); + } + } + } + + return newNetId == netIdField; + } + + // helper function for [SyncVar] GameObjects. + // dirtyBit is a mask like 00010 + protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gameObjectField, ulong dirtyBit, ref uint netIdField) + { + if (GetSyncVarHookGuard(dirtyBit)) + return; + + uint newNetId = 0; + if (newGameObject != null) + { + if (newGameObject.TryGetComponent(out NetworkIdentity identity)) + { + newNetId = identity.netId; + if (newNetId == 0) + { + Debug.LogWarning($"SetSyncVarGameObject GameObject {newGameObject} has a zero netId. Maybe it is not spawned yet?"); + } + } + } + + //Debug.Log($"SetSyncVar GameObject {GetType().Name} bit:{dirtyBit} netfieldId:{netIdField} -> {newNetId}"); + SetSyncVarDirtyBit(dirtyBit); + // assign new one on the server, and in case we ever need it on client too + gameObjectField = newGameObject; + netIdField = newNetId; + } + + // helper function for [SyncVar] GameObjects. + // -> ref GameObject as second argument makes OnDeserialize processing easier + protected GameObject GetSyncVarGameObject(uint netId, ref GameObject gameObjectField) + { + // server always uses the field + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) + { + return gameObjectField; + } + + // client always looks up based on netId because objects might get in and out of range + // over and over again, which shouldn't null them forever + if (NetworkClient.spawned.TryGetValue(netId, out NetworkIdentity identity) && identity != null) + return gameObjectField = identity.gameObject; + return null; + } + + // helper function for [SyncVar] NetworkIdentities. + // needs to be public so that tests & NetworkBehaviours from other + // assemblies both find it + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool SyncVarNetworkIdentityEqual(NetworkIdentity newIdentity, uint netIdField) + { + uint newNetId = 0; + if (newIdentity != null) + { + newNetId = newIdentity.netId; + if (newNetId == 0) + { + Debug.LogWarning($"SetSyncVarNetworkIdentity NetworkIdentity {newIdentity} has a zero netId. Maybe it is not spawned yet?"); + } + } + + // netId changed? + return newNetId == netIdField; + } + + // move the [SyncVar] generated OnDeserialize C# to avoid much IL. + // + // before: + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // int num = health; + // Networkhealth = reader.ReadInt(); + // if (!NetworkBehaviour.SyncVarEqual(num, ref health)) + // { + // OnChanged(num, health); + // } + // return; + // } + // long num2 = (long)reader.ReadULong(); + // if ((num2 & 1L) != 0L) + // { + // int num3 = health; + // Networkhealth = reader.ReadInt(); + // if (!NetworkBehaviour.SyncVarEqual(num3, ref health)) + // { + // OnChanged(num3, health); + // } + // } + // } + // + // after: + // + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // GeneratedSyncVarDeserialize(reader, ref health, null, reader.ReadInt()); + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // GeneratedSyncVarDeserialize(reader, ref health, null, reader.ReadInt()); + // } + // } + public void GeneratedSyncVarDeserialize(ref T field, Action OnChanged, T value) + { + T previous = field; + field = value; + + // any hook? then call if changed. + if (OnChanged != null && !SyncVarEqual(previous, ref field)) + { + OnChanged(previous, field); + } + } + + // move the [SyncVar] generated OnDeserialize C# to avoid much IL. + // + // before: + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // uint __targetNetId = ___targetNetId; + // GameObject networktarget = Networktarget; + // ___targetNetId = reader.ReadUInt(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId, ref ___targetNetId)) + // { + // OnChangedNB(networktarget, Networktarget); + // } + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // uint __targetNetId2 = ___targetNetId; + // GameObject networktarget2 = Networktarget; + // ___targetNetId = reader.ReadUInt(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId2, ref ___targetNetId)) + // { + // OnChangedNB(networktarget2, Networktarget); + // } + // } + // } + // + // after: + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // GeneratedSyncVarDeserialize_GameObject(reader, ref target, OnChangedNB, ref ___targetNetId); + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // GeneratedSyncVarDeserialize_GameObject(reader, ref target, OnChangedNB, ref ___targetNetId); + // } + // } + public void GeneratedSyncVarDeserialize_GameObject(ref GameObject field, Action OnChanged, NetworkReader reader, ref uint netIdField) + { + uint previousNetId = netIdField; + GameObject previousGameObject = field; + netIdField = reader.ReadUInt(); + + // get the new GameObject now that netId field is set + field = GetSyncVarGameObject(netIdField, ref field); + + // any hook? then call if changed. + if (OnChanged != null && !SyncVarEqual(previousNetId, ref netIdField)) + { + OnChanged(previousGameObject, field); + } + } + + // move the [SyncVar] generated OnDeserialize C# to avoid much IL. + // + // before: + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // uint __targetNetId = ___targetNetId; + // NetworkIdentity networktarget = Networktarget; + // ___targetNetId = reader.ReadUInt(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId, ref ___targetNetId)) + // { + // OnChangedNI(networktarget, Networktarget); + // } + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // uint __targetNetId2 = ___targetNetId; + // NetworkIdentity networktarget2 = Networktarget; + // ___targetNetId = reader.ReadUInt(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId2, ref ___targetNetId)) + // { + // OnChangedNI(networktarget2, Networktarget); + // } + // } + // } + // + // after: + // + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // GeneratedSyncVarDeserialize_NetworkIdentity(reader, ref target, OnChangedNI, ref ___targetNetId); + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // GeneratedSyncVarDeserialize_NetworkIdentity(reader, ref target, OnChangedNI, ref ___targetNetId); + // } + // } + public void GeneratedSyncVarDeserialize_NetworkIdentity(ref NetworkIdentity field, Action OnChanged, NetworkReader reader, ref uint netIdField) + { + uint previousNetId = netIdField; + NetworkIdentity previousIdentity = field; + netIdField = reader.ReadUInt(); + + // get the new NetworkIdentity now that netId field is set + field = GetSyncVarNetworkIdentity(netIdField, ref field); + + // any hook? then call if changed. + if (OnChanged != null && !SyncVarEqual(previousNetId, ref netIdField)) + { + OnChanged(previousIdentity, field); + } + } + + // move the [SyncVar] generated OnDeserialize C# to avoid much IL. + // + // before: + // + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // NetworkBehaviourSyncVar __targetNetId = ___targetNetId; + // Tank networktarget = Networktarget; + // ___targetNetId = reader.ReadNetworkBehaviourSyncVar(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId, ref ___targetNetId)) + // { + // OnChangedNB(networktarget, Networktarget); + // } + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // NetworkBehaviourSyncVar __targetNetId2 = ___targetNetId; + // Tank networktarget2 = Networktarget; + // ___targetNetId = reader.ReadNetworkBehaviourSyncVar(); + // if (!NetworkBehaviour.SyncVarEqual(__targetNetId2, ref ___targetNetId)) + // { + // OnChangedNB(networktarget2, Networktarget); + // } + // } + // } + // + // after: + // + // public override void DeserializeSyncVars(NetworkReader reader, bool initialState) + // { + // base.DeserializeSyncVars(reader, initialState); + // if (initialState) + // { + // GeneratedSyncVarDeserialize_NetworkBehaviour(reader, ref target, OnChangedNB, ref ___targetNetId); + // return; + // } + // long num = (long)reader.ReadULong(); + // if ((num & 1L) != 0L) + // { + // GeneratedSyncVarDeserialize_NetworkBehaviour(reader, ref target, OnChangedNB, ref ___targetNetId); + // } + // } + public void GeneratedSyncVarDeserialize_NetworkBehaviour(ref T field, Action OnChanged, NetworkReader reader, ref NetworkBehaviourSyncVar netIdField) + where T : NetworkBehaviour + { + NetworkBehaviourSyncVar previousNetId = netIdField; + T previousBehaviour = field; + netIdField = reader.ReadNetworkBehaviourSyncVar(); + + // get the new NetworkBehaviour now that netId field is set + field = GetSyncVarNetworkBehaviour(netIdField, ref field); + + // any hook? then call if changed. + if (OnChanged != null && !SyncVarEqual(previousNetId, ref netIdField)) + { + OnChanged(previousBehaviour, field); + } + } + + // helper function for [SyncVar] NetworkIdentities. + // dirtyBit is a mask like 00010 + protected void SetSyncVarNetworkIdentity(NetworkIdentity newIdentity, ref NetworkIdentity identityField, ulong dirtyBit, ref uint netIdField) + { + if (GetSyncVarHookGuard(dirtyBit)) + return; + + uint newNetId = 0; + if (newIdentity != null) + { + newNetId = newIdentity.netId; + if (newNetId == 0) + { + Debug.LogWarning($"SetSyncVarNetworkIdentity NetworkIdentity {newIdentity} has a zero netId. Maybe it is not spawned yet?"); + } + } + + //Debug.Log($"SetSyncVarNetworkIdentity NetworkIdentity {GetType().Name} bit:{dirtyBit} netIdField:{netIdField} -> {newNetId}"); + SetSyncVarDirtyBit(dirtyBit); + netIdField = newNetId; + // assign new one on the server, and in case we ever need it on client too + identityField = newIdentity; + } + + // helper function for [SyncVar] NetworkIdentities. + // -> ref GameObject as second argument makes OnDeserialize processing easier + protected NetworkIdentity GetSyncVarNetworkIdentity(uint netId, ref NetworkIdentity identityField) + { + // server always uses the field + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) + { + return identityField; + } + + // client always looks up based on netId because objects might get in and out of range + // over and over again, which shouldn't null them forever + NetworkClient.spawned.TryGetValue(netId, out identityField); + return identityField; + } + + protected static bool SyncVarNetworkBehaviourEqual(T newBehaviour, NetworkBehaviourSyncVar syncField) where T : NetworkBehaviour + { + uint newNetId = 0; + byte newComponentIndex = 0; + if (newBehaviour != null) + { + newNetId = newBehaviour.netId; + newComponentIndex = newBehaviour.ComponentIndex; + if (newNetId == 0) + { + Debug.LogWarning($"SetSyncVarNetworkIdentity NetworkIdentity {newBehaviour} has a zero netId. Maybe it is not spawned yet?"); + } + } + + // netId changed? + return syncField.Equals(newNetId, newComponentIndex); + } + + // helper function for [SyncVar] NetworkIdentities. + // dirtyBit is a mask like 00010 + protected void SetSyncVarNetworkBehaviour(T newBehaviour, ref T behaviourField, ulong dirtyBit, ref NetworkBehaviourSyncVar syncField) where T : NetworkBehaviour + { + if (GetSyncVarHookGuard(dirtyBit)) + return; + + uint newNetId = 0; + byte componentIndex = 0; + if (newBehaviour != null) + { + newNetId = newBehaviour.netId; + componentIndex = newBehaviour.ComponentIndex; + if (newNetId == 0) + { + Debug.LogWarning($"{nameof(SetSyncVarNetworkBehaviour)} NetworkIdentity {newBehaviour} has a zero netId. Maybe it is not spawned yet?"); + } + } + + syncField = new NetworkBehaviourSyncVar(newNetId, componentIndex); + + SetSyncVarDirtyBit(dirtyBit); + + // assign new one on the server, and in case we ever need it on client too + behaviourField = newBehaviour; + + // Debug.Log($"SetSyncVarNetworkBehaviour NetworkIdentity {GetType().Name} bit [{dirtyBit}] netIdField:{oldField}->{syncField}"); + } + + // helper function for [SyncVar] NetworkBehaviours. + // -> ref GameObject as second argument makes OnDeserialize processing easier + protected T GetSyncVarNetworkBehaviour(NetworkBehaviourSyncVar syncNetBehaviour, ref T behaviourField) where T : NetworkBehaviour + { + // server always uses the field + // if neither, fallback to original field + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3447 + if (isServer || !isClient) + { + return behaviourField; + } + + // client always looks up based on netId because objects might get in and out of range + // over and over again, which shouldn't null them forever + if (!NetworkClient.spawned.TryGetValue(syncNetBehaviour.netId, out NetworkIdentity identity)) + { + return null; + } + + // ensure componentIndex is in range. + // show explicit errors if something went wrong, instead of IndexOutOfRangeException. + // removing components at runtime isn't allowed, yet this happened in a project so we need to check for it. + if (syncNetBehaviour.componentIndex >= identity.NetworkBehaviours.Length) + { + Debug.LogError($"[SyncVar] {typeof(T)} on {name}'s {GetType()}: can't access {identity.name} NetworkBehaviour[{syncNetBehaviour.componentIndex}] because it only has {identity.NetworkBehaviours.Length} components.\nWas a NetworkBeahviour accidentally destroyed at runtime?"); + return null; + } + + behaviourField = identity.NetworkBehaviours[syncNetBehaviour.componentIndex] as T; + return behaviourField; + } + + protected static bool SyncVarEqual(T value, ref T fieldValue) + { + // newly initialized or changed value? + // value.Equals(fieldValue) allocates without 'where T : IEquatable' + // seems like we use EqualityComparer to avoid allocations, + // because not all SyncVars are IEquatable + return EqualityComparer.Default.Equals(value, fieldValue); + } + + // dirtyBit is a mask like 00010 + protected void SetSyncVar(T value, ref T fieldValue, ulong dirtyBit) + { + //Debug.Log($"SetSyncVar {GetType().Name} bit:{dirtyBit} fieldValue:{value}"); + SetSyncVarDirtyBit(dirtyBit); + fieldValue = value; + } + + /// Override to do custom serialization (instead of SyncVars/SyncLists). Use OnDeserialize too. + // if a class has syncvars, then OnSerialize/OnDeserialize are added + // automatically. + // + // initialState is true for full spawns, false for delta syncs. + // note: SyncVar hooks are only called when inital=false + public virtual void OnSerialize(NetworkWriter writer, bool initialState) + { + SerializeSyncObjects(writer, initialState); + SerializeSyncVars(writer, initialState); + } + + /// Override to do custom deserialization (instead of SyncVars/SyncLists). Use OnSerialize too. + public virtual void OnDeserialize(NetworkReader reader, bool initialState) + { + DeserializeSyncObjects(reader, initialState); + DeserializeSyncVars(reader, initialState); + } + + void SerializeSyncObjects(NetworkWriter writer, bool initialState) + { + // if initialState: write all SyncObjects (SyncList/Set/etc) + // otherwise write dirtyBits+dirty SyncVars + if (initialState) + SerializeObjectsAll(writer); + else + SerializeObjectsDelta(writer); + } + + void DeserializeSyncObjects(NetworkReader reader, bool initialState) + { + if (initialState) + { + DeserializeObjectsAll(reader); + } + else + { + DeserializeObjectsDelta(reader); + } + } + + // USED BY WEAVER + protected virtual void SerializeSyncVars(NetworkWriter writer, bool initialState) + { + // SyncVar are written here in subclass + + // if initialState + // write all SyncVars + // else + // write syncVarDirtyBits + // write dirty SyncVars + } + + // USED BY WEAVER + protected virtual void DeserializeSyncVars(NetworkReader reader, bool initialState) + { + // SyncVars are read here in subclass + + // if initialState + // read all SyncVars + // else + // read syncVarDirtyBits + // read dirty SyncVars + } + + public void SerializeObjectsAll(NetworkWriter writer) + { + for (int i = 0; i < syncObjects.Count; i++) + { + SyncObject syncObject = syncObjects[i]; + syncObject.OnSerializeAll(writer); + } + } + + public void SerializeObjectsDelta(NetworkWriter writer) + { + // write the mask + writer.WriteULong(syncObjectDirtyBits); + + // serializable objects, such as synclists + for (int i = 0; i < syncObjects.Count; i++) + { + // check dirty mask at nth bit + SyncObject syncObject = syncObjects[i]; + if ((syncObjectDirtyBits & (1UL << i)) != 0) + { + syncObject.OnSerializeDelta(writer); + } + } + } + + internal void DeserializeObjectsAll(NetworkReader reader) + { + for (int i = 0; i < syncObjects.Count; i++) + { + SyncObject syncObject = syncObjects[i]; + syncObject.OnDeserializeAll(reader); + } + } + + internal void DeserializeObjectsDelta(NetworkReader reader) + { + ulong dirty = reader.ReadULong(); + for (int i = 0; i < syncObjects.Count; i++) + { + // check dirty mask at nth bit + SyncObject syncObject = syncObjects[i]; + if ((dirty & (1UL << i)) != 0) + { + syncObject.OnDeserializeDelta(reader); + } + } + } + + // safely serialize each component in a way that one reading too much or + // too few bytes will show obvious, easy to resolve error messages. + // + // prevents the original UNET bug which started Mirror: + // https://github.com/vis2k/Mirror/issues/2617 + // where one component would read too much, and then all following reads + // on other entities would be mismatched, causing the weirdest errors. + // + // reads <> for 100% safety. + internal void Serialize(NetworkWriter writer, bool initialState) + { + // reserve length header to ensure the correct amount will be read. + // originally we used a 4 byte header (too bandwidth heavy). + // instead, let's "& 0xFF" the size. + // + // this is cleaner than barriers at the end of payload, because: + // - ensures the correct safety is read _before_ payload. + // - it's quite hard to break the check. + // a component would need to read/write the intented amount + // multiplied by 255 in order to miss the check. + // with barriers, reading 1 byte too much may still succeed if the + // next component's first byte matches the expected barrier. + // - we can still attempt to correct the invalid position via the + // safety length byte (we know that one is correct). + // + // it's just overall cleaner, and still low on bandwidth. + + // write placeholder length byte + // (jumping back later is WAY faster than allocating a temporary + // writer for the payload, then writing payload.size, payload) + int headerPosition = writer.Position; + writer.WriteByte(0); + int contentPosition = writer.Position; + + // write payload + try + { + // note this may not write anything if no syncIntervals elapsed + OnSerialize(writer, initialState); + } + catch (Exception e) + { + // show a detailed error and let the user know what went wrong + Debug.LogError($"OnSerialize failed for: object={name} component={GetType()} sceneId={netIdentity.sceneId:X}\n\n{e}"); + } + int endPosition = writer.Position; + + // fill in length hash as the last byte of the 4 byte length + writer.Position = headerPosition; + int size = endPosition - contentPosition; + byte safety = (byte)(size & 0xFF); + writer.WriteByte(safety); + writer.Position = endPosition; + + //Debug.Log($"OnSerializeSafely written for object {name} component:{GetType()} sceneId:{sceneId:X} header:{headerPosition} content:{contentPosition} end:{endPosition} contentSize:{endPosition - contentPosition}"); + } + + // correct the read size with the 1 byte length hash (by mischa). + // -> the component most likely read a few too many/few bytes. + // -> we know the correct last byte of the expected size (=the safety). + // -> attempt to reconstruct the size via safety byte. + // it will be correct unless someone wrote way way too much, + // as in > 255 bytes worth too much. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int ErrorCorrection(int size, byte safety) + { + // clear the last byte which most likely contains the error + uint cleared = (uint)size & 0xFFFFFF00; + + // insert the safety which we know to be correct + return (int)(cleared | safety); + } + + // returns false in case of errors. + // server needs to know in order to disconnect on error. + internal bool Deserialize(NetworkReader reader, bool initialState) + { + // detect errors, but attempt to correct before returning + bool result = true; + + // read 1 byte length hash safety & capture beginning for size check + byte safety = reader.ReadByte(); + int chunkStart = reader.Position; + + // call OnDeserialize and wrap it in a try-catch block so there's no + // way to mess up another component's deserialization + try + { + //Debug.Log($"OnDeserializeSafely: {name} component:{GetType()} sceneId:{sceneId:X} length:{contentSize}"); + OnDeserialize(reader, initialState); + } + catch (Exception e) + { + // show a detailed error and let the user know what went wrong + Debug.LogError($"OnDeserialize failed Exception={e.GetType()} (see below) object={name} component={GetType()} netId={netId}. Possible Reasons:\n" + + $" * Do {GetType()}'s OnSerialize and OnDeserialize calls write the same amount of data? \n" + + $" * Was there an exception in {GetType()}'s OnSerialize/OnDeserialize code?\n" + + $" * Are the server and client the exact same project?\n" + + $" * Maybe this OnDeserialize call was meant for another GameObject? The sceneIds can easily get out of sync if the Hierarchy was modified only in the client OR the server. Try rebuilding both.\n\n" + + $"Exception {e}"); + result = false; + } + + // compare bytes read with length hash + int size = reader.Position - chunkStart; + byte sizeHash = (byte)(size & 0xFF); + if (sizeHash != safety) + { + // warn the user. + Debug.LogWarning($"{name} (netId={netId}): {GetType()} OnDeserialize size mismatch. It read {size} bytes, which caused a size hash mismatch of {sizeHash:X2} vs. {safety:X2}. Make sure that OnSerialize and OnDeserialize write/read the same amount of data in all cases."); + + // attempt to fix the position, so the following components + // don't all fail. this is very likely to work, unless the user + // read more than 255 bytes too many / too few. + // + // see test: SerializationSizeMismatch. + int correctedSize = ErrorCorrection(size, safety); + reader.Position = chunkStart + correctedSize; + result = false; + } + + return result; + } + + internal void ResetSyncObjects() + { + foreach (SyncObject syncObject in syncObjects) + { + syncObject.Reset(); + } + } + + /// Like Start(), but only called on server and host. + public virtual void OnStartServer() {} + + /// Stop event, only called on server and host. + public virtual void OnStopServer() {} + + /// Like Start(), but only called on client and host. + public virtual void OnStartClient() {} + + /// Stop event, only called on client and host. + public virtual void OnStopClient() {} + + /// Like Start(), but only called on client and host for the local player object. + public virtual void OnStartLocalPlayer() {} + + /// Stop event, but only called on client and host for the local player object. + public virtual void OnStopLocalPlayer() {} + + /// Like Start(), but only called for objects the client has authority over. + public virtual void OnStartAuthority() {} + + /// Stop event, only called for objects the client has authority over. + public virtual void OnStopAuthority() {} + + // Weaver injects this into inheriting classes to return true. + // allows runtime & tests to check if a type was weaved. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual bool Weaved() => false; + } +} diff --git a/Assets/Mirror/Core/NetworkBehaviour.cs.meta b/Assets/Mirror/Core/NetworkBehaviour.cs.meta new file mode 100644 index 0000000..3c6e6f5 --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 655ee8cba98594f70880da5cc4dc442d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkBehaviour.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkBehaviourHybrid.cs b/Assets/Mirror/Core/NetworkBehaviourHybrid.cs new file mode 100644 index 0000000..988c5cc --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviourHybrid.cs @@ -0,0 +1,483 @@ +// base class for "Hybrid" sync components. +// inspired by the Quake networking model, but made to scale. +// https://www.jfedor.org/quake3/ +using System; +using UnityEngine; + +namespace Mirror +{ + public abstract class NetworkBehaviourHybrid : NetworkBehaviour + { + // Is this a client with authority over this transform? + // This component could be on the player object or any object that has been assigned authority to this client. + protected bool IsClientWithAuthority => isClient && authority; + + [Tooltip("Occasionally send a full reliable state to delta compress against. This only applies to Components with SyncMethod=Unreliable.")] + public int baselineRate = 1; + public float baselineInterval => baselineRate < int.MaxValue ? 1f / baselineRate : 0; // for 1 Hz, that's 1000ms + protected double lastBaselineTime; + protected double lastDeltaTime; + + // delta compression needs to remember 'last' to compress against. + byte lastSerializedBaselineTick = 0; + byte lastDeserializedBaselineTick = 0; + + [Tooltip("Enable to send all unreliable messages twice. Only useful for extremely fast-paced games since it doubles bandwidth costs.")] + public bool unreliableRedundancy = false; + + [Tooltip("When sending a reliable baseline, should we also send an unreliable delta or rely on the reliable baseline to arrive in a similar time?")] + public bool baselineIsDelta = true; + + // change detection: we need to do this carefully in order to get it right. + // + // DONT just check changes in UpdateBaseline(). this would introduce MrG's grid issue: + // server start in A1, reliable baseline sent to client + // server moves to A2, unreliabe delta sent to client + // server moves to A1, nothing is sent to client becuase last baseline position == position + // => client wouldn't know we moved back to A1 + // + // INSTEAD: every update() check for changes since baseline: + // UpdateDelta() keeps sending only if changed since _baseline_ + // UpdateBaseline() resends if there was any change in the period since last baseline. + // => this avoids the A1->A2->A1 grid issue above + bool changedSinceBaseline = false; + + [Header("Debug")] + public bool debugLog = false; + + public virtual void ResetState() + { + lastSerializedBaselineTick = 0; + lastDeserializedBaselineTick = 0; + changedSinceBaseline = false; + } + + // user callbacks ////////////////////////////////////////////////////// + protected abstract void OnSerializeBaseline(NetworkWriter writer); + protected abstract void OnDeserializeBaseline(NetworkReader reader, byte baselineTick); + + protected abstract void OnSerializeDelta(NetworkWriter writer); + protected abstract void OnDeserializeDelta(NetworkReader reader, byte baselineTick); + + // implementations must store the current baseline state when requested: + // - implementations can use this to compress deltas against + // - implementations can use this to detect changes since baseline + // this is called whenever a baseline was sent. + protected abstract void StoreState(); + + // implementations may compare current state to the last stored state. + // this way we only need to send another reliable baseline if changed since last. + // this is called every syncInterval, not every baseline sync interval. + // (see comments where this is called). + protected abstract bool StateChanged(); + + // user callback in case drops due to baseline mismatch need to be logged/visualized/debugged. + protected virtual void OnDrop(byte lastBaselineTick, byte baselineTick, NetworkReader reader) {} + + // rpcs / cmds ///////////////////////////////////////////////////////// + // reliable baseline. + // include owner in case of server authority. + [ClientRpc(channel = Channels.Reliable)] + void RpcServerToClientBaseline(ArraySegment data) + { + // baseline is broadcast to all clients. + // ignore if this object is owned by this client. + if (IsClientWithAuthority) return; + + // host mode: baseline Rpc is also sent through host's local connection and applied. + // applying host's baseline as last deserialized would overwrite the owner client's data and cause jitter. + // in other words: never apply the rpcs in host mode. + if (isServer) return; + + using (NetworkReaderPooled reader = NetworkReaderPool.Get(data)) + { + // deserialize + // save last deserialized baseline tick number to compare deltas against + lastDeserializedBaselineTick = reader.ReadByte(); + OnDeserializeBaseline(reader, lastDeserializedBaselineTick); + } + } + + // unreliable delta. + // include owner in case of server authority. + [ClientRpc(channel = Channels.Unreliable)] + void RpcServerToClientDelta(ArraySegment data) + { + // delta is broadcast to all clients. + // ignore if this object is owned by this client. + if (IsClientWithAuthority) return; + + // host mode: baseline Rpc is also sent through host's local connection and applied. + // applying host's baseline as last deserialized would overwrite the owner client's data and cause jitter. + // in other words: never apply the rpcs in host mode. + if (isServer) return; + + // deserialize + using (NetworkReaderPooled reader = NetworkReaderPool.Get(data)) + { + // deserialize + byte baselineTick = reader.ReadByte(); + + // ensure this delta is for our last known baseline. + // we should never apply a delta on top of a wrong baseline. + if (baselineTick != lastDeserializedBaselineTick) + { + OnDrop(lastDeserializedBaselineTick, baselineTick, reader); + + // this can happen if unreliable arrives before reliable etc. + // no need to log this except when debugging. + if (debugLog) Debug.Log($"[{name}] Client: received delta for wrong baseline #{baselineTick}. Last was {lastDeserializedBaselineTick}. Ignoring."); + return; + } + + OnDeserializeDelta(reader, baselineTick); + } + } + + [Command(channel = Channels.Reliable)] // reliable baseline + void CmdClientToServerBaseline(ArraySegment data) + { + // deserialize + using (NetworkReaderPooled reader = NetworkReaderPool.Get(data)) + { + // deserialize + lastDeserializedBaselineTick = reader.ReadByte(); + OnDeserializeBaseline(reader, lastDeserializedBaselineTick); + } + } + + [Command(channel = Channels.Unreliable)] // unreliable delta + void CmdClientToServerDelta(ArraySegment data) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(data)) + { + // deserialize + byte baselineTick = reader.ReadByte(); + + // ensure this delta is for our last known baseline. + // we should never apply a delta on top of a wrong baseline. + if (baselineTick != lastDeserializedBaselineTick) + { + OnDrop(lastDeserializedBaselineTick, baselineTick, reader); + + // this can happen if unreliable arrives before reliable etc. + // no need to log this except when debugging. + if (debugLog) Debug.Log($"[{name}] Server: received delta for wrong baseline #{baselineTick} from: {connectionToClient}. Last was {lastDeserializedBaselineTick}. Ignoring."); + return; + } + + OnDeserializeDelta(reader, baselineTick); + } + } + + // update server /////////////////////////////////////////////////////// + protected virtual void UpdateServerBaseline(double localTime) + { + // send a reliable baseline every 1 Hz + if (localTime < lastBaselineTime + baselineInterval) return; + + // only sync if changed since last reliable baseline + if (!changedSinceBaseline) return; + + // save bandwidth by only transmitting what is needed. + // -> ArraySegment with random data is slower since byte[] copying + // -> Vector3? and Quaternion? nullables takes more bandwidth + byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // serialize + writer.WriteByte(frameCount); + OnSerializeBaseline(writer); + + // send (no need for redundancy since baseline is reliable) + RpcServerToClientBaseline(writer); + } + + // save the last baseline's tick number. + // included in baseline to identify which one it was on client + // included in deltas to ensure they are on top of the correct baseline + lastSerializedBaselineTick = frameCount; + lastBaselineTime = NetworkTime.localTime; + + // perf. & bandwidth optimization: + // send a delta right after baseline to avoid potential head of + // line blocking, or skip the delta whenever we sent reliable? + // for example: + // 1 Hz baseline + // 10 Hz delta + // => 11 Hz total if we still send delta after reliable + // => 10 Hz total if we skip delta after reliable + // in that case, skip next delta by simply resetting last delta sync's time. + if (baselineIsDelta) lastDeltaTime = localTime; + + // request to store last baseline state (i.e. position) for change detection. + StoreState(); + + // baseline was just sent after a change. reset change detection. + changedSinceBaseline = false; + + if (debugLog) Debug.Log($"[{name}] Server: sent baseline #{lastSerializedBaselineTick} to: {connectionToClient} at time: {localTime}"); + } + + protected virtual void UpdateServerDelta(double localTime) + { + // broadcast to all clients each 'sendInterval' + // (client with authority will drop the rpc) + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + // + // Checks to ensure server only sends snapshots if object is + // on server authority(!clientAuthority) mode because on client + // authority mode snapshots are broadcasted right after the authoritative + // client updates server in the command function(see above), OR, + // since host does not send anything to update the server, any client + // authoritative movement done by the host will have to be broadcasted + // here by checking IsClientWithAuthority. + // TODO send same time that NetworkServer sends time snapshot? + + if (localTime < lastDeltaTime + syncInterval) return; + + // look for changes every unreliable sendInterval! + // every reliable interval isn't enough, this would cause MrG's grid issue: + // server start in A1, reliable baseline sent to clients + // server moves to A2, unreliabe delta sent to clients + // server moves back to A1, nothing is sent to clients because last baseline position == position + // => clients wouldn't know we moved back to A1 + // every update works, but it's unnecessary overhead since sends only happen every sendInterval + // every unreliable sendInterval is the perfect place to look for changes. + if (StateChanged()) changedSinceBaseline = true; + + // only sync on change: + // unreliable isn't guaranteed to be delivered so this depends on reliable baseline. + if (!changedSinceBaseline) return; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // serialize + writer.WriteByte(lastSerializedBaselineTick); + OnSerializeDelta(writer); + + // send (with optional redundancy to make up for message drops) + RpcServerToClientDelta(writer); + if (unreliableRedundancy) + RpcServerToClientDelta(writer); + } + + lastDeltaTime = localTime; + + if (debugLog) Debug.Log($"[{name}] Server: sent delta for #{lastSerializedBaselineTick} to: {connectionToClient} at time: {localTime}"); + } + + protected virtual void UpdateServerSync() + { + // server broadcasts all objects all the time. + // -> not just ServerToClient: ClientToServer need to be broadcast to others too + + // perf: only grab NetworkTime.localTime property once. + double localTime = NetworkTime.localTime; + + // broadcast + UpdateServerBaseline(localTime); + UpdateServerDelta(localTime); + } + + // update client /////////////////////////////////////////////////////// + protected virtual void UpdateClientBaseline(double localTime) + { + // send a reliable baseline every 1 Hz + if (localTime < lastBaselineTime + baselineInterval) return; + + // only sync if changed since last reliable baseline + if (!changedSinceBaseline) return; + + // save bandwidth by only transmitting what is needed. + // -> ArraySegment with random data is slower since byte[] copying + // -> Vector3? and Quaternion? nullables takes more bandwidth + byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // serialize + writer.WriteByte(frameCount); + OnSerializeBaseline(writer); + + // send (no need for redundancy since baseline is reliable) + CmdClientToServerBaseline(writer); + } + + // save the last baseline's tick number. + // included in baseline to identify which one it was on client + // included in deltas to ensure they are on top of the correct baseline + lastSerializedBaselineTick = frameCount; + lastBaselineTime = NetworkTime.localTime; + + // perf. & bandwidth optimization: + // send a delta right after baseline to avoid potential head of + // line blocking, or skip the delta whenever we sent reliable? + // for example: + // 1 Hz baseline + // 10 Hz delta + // => 11 Hz total if we still send delta after reliable + // => 10 Hz total if we skip delta after reliable + // in that case, skip next delta by simply resetting last delta sync's time. + if (baselineIsDelta) lastDeltaTime = localTime; + + // request to store last baseline state (i.e. position) for change detection. + // IMPORTANT + // OnSerialize(initial) is called for the spawn payload whenever + // someone starts observing this object. we always must make + // this the new baseline, otherwise this happens: + // - server broadcasts baseline @ t=1 + // - server broadcasts delta for baseline @ t=1 + // - ... time passes ... + // - new observer -> OnSerialize sends current position @ t=2 + // - server broadcasts delta for baseline @ t=1 + // => client's baseline is t=2 but receives delta for t=1 _!_ + StoreState(); + + // baseline was just sent after a change. reset change detection. + changedSinceBaseline = false; + + if (debugLog) Debug.Log($"[{name}] Client: sent baseline #{lastSerializedBaselineTick} at time: {localTime}"); + } + + protected virtual void UpdateClientDelta(double localTime) + { + // send to server each 'sendInterval' + // NetworkTime.localTime for double precision until Unity has it too + // + // IMPORTANT: + // snapshot interpolation requires constant sending. + // DO NOT only send if position changed. for example: + // --- + // * client sends first position at t=0 + // * ... 10s later ... + // * client moves again, sends second position at t=10 + // --- + // * server gets first position at t=0 + // * server gets second position at t=10 + // * server moves from first to second within a time of 10s + // => would be a super slow move, instead of a wait & move. + // + // IMPORTANT: + // DO NOT send nulls if not changed 'since last send' either. we + // send unreliable and don't know which 'last send' the other end + // received successfully. + + if (localTime < lastDeltaTime + syncInterval) return; + + // look for changes every unreliable sendInterval! + // every reliable interval isn't enough, this would cause MrG's grid issue: + // client start in A1, reliable baseline sent to server and other clients + // client moves to A2, unreliabe delta sent to server and other clients + // client moves back to A1, nothing is sent to server because last baseline position == position + // => server / other clients wouldn't know we moved back to A1 + // every update works, but it's unnecessary overhead since sends only happen every sendInterval + // every unreliable sendInterval is the perfect place to look for changes. + if (StateChanged()) changedSinceBaseline = true; + + // only sync on change: + // unreliable isn't guaranteed to be delivered so this depends on reliable baseline. + if (!changedSinceBaseline) return; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // serialize + writer.WriteByte(lastSerializedBaselineTick); + OnSerializeDelta(writer); + + // send (with optional redundancy to make up for message drops) + CmdClientToServerDelta(writer); + if (unreliableRedundancy) + CmdClientToServerDelta(writer); + } + + lastDeltaTime = localTime; + + if (debugLog) Debug.Log($"[{name}] Client: sent delta for #{lastSerializedBaselineTick} at time: {localTime}"); + } + + protected virtual void UpdateClientSync() + { + // client authority, and local player (= allowed to move myself)? + if (IsClientWithAuthority) + { + // https://github.com/vis2k/Mirror/pull/2992/ + if (!NetworkClient.ready) return; + + // perf: only grab NetworkTime.localTime property once. + double localTime = NetworkTime.localTime; + + UpdateClientBaseline(localTime); + UpdateClientDelta(localTime); + } + } + + // Update() without LateUpdate() split: otherwise perf. is cut in half! + protected virtual void Update() + { + // if server then always sync to others. + if (isServer) UpdateServerSync(); + // 'else if' because host mode shouldn't send anything to server. + // it is the server. don't overwrite anything there. + else if (isClient) UpdateClientSync(); + } + + // OnSerialize(initial) is called every time when a player starts observing us. + // note this is _not_ called just once on spawn. + // call this from inheriting classes immediately in OnSerialize(). + public override void OnSerialize(NetworkWriter writer, bool initialState) + { + if (initialState) + { + // always include the tick for deltas to compare against. + byte frameCount = (byte)Time.frameCount; // perf: only access Time.frameCount once! + writer.WriteByte(frameCount); + + // IMPORTANT + // OnSerialize(initial) is called for the spawn payload whenever + // someone starts observing this object. we always must make + // this the new baseline, otherwise this happens: + // - server broadcasts baseline @ t=1 + // - server broadcasts delta for baseline @ t=1 + // - ... time passes ... + // - new observer -> OnSerialize sends current position @ t=2 + // - server broadcasts delta for baseline @ t=1 + // => client's baseline is t=2 but receives delta for t=1 _!_ + lastSerializedBaselineTick = (byte)Time.frameCount; + lastBaselineTime = NetworkTime.localTime; + + // request to store last baseline state (i.e. position) for change detection. + StoreState(); + } + } + + // call this from inheriting classes immediately in OnDeserialize(). + public override void OnDeserialize(NetworkReader reader, bool initialState) + { + if (initialState) + { + // save last deserialized baseline tick number to compare deltas against + lastDeserializedBaselineTick = reader.ReadByte(); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkBehaviourHybrid.cs.meta b/Assets/Mirror/Core/NetworkBehaviourHybrid.cs.meta new file mode 100644 index 0000000..bfa737d --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviourHybrid.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 657535a722c74173bdaa18a4394ce016 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkBehaviourHybrid.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs b/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs new file mode 100644 index 0000000..e9ed726 --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs @@ -0,0 +1,33 @@ +using System; + +namespace Mirror +{ + // backing field for sync NetworkBehaviour + public struct NetworkBehaviourSyncVar : IEquatable + { + public uint netId; + // limited to 255 behaviours per identity + public byte componentIndex; + + public NetworkBehaviourSyncVar(uint netId, int componentIndex) : this() + { + this.netId = netId; + this.componentIndex = (byte)componentIndex; + } + + public bool Equals(NetworkBehaviourSyncVar other) + { + return other.netId == netId && other.componentIndex == componentIndex; + } + + public bool Equals(uint netId, int componentIndex) + { + return this.netId == netId && this.componentIndex == componentIndex; + } + + public override string ToString() + { + return $"[netId:{netId} compIndex:{componentIndex}]"; + } + } +} diff --git a/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs.meta b/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs.meta new file mode 100644 index 0000000..0a925a7 --- /dev/null +++ b/Assets/Mirror/Core/NetworkBehaviourSyncVar.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b04fe7518657486089dfaf811db0b3ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkBehaviourSyncVar.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs new file mode 100644 index 0000000..d9cce5a --- /dev/null +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -0,0 +1,1885 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mirror.RemoteCalls; +using UnityEngine; + +namespace Mirror +{ + public enum ConnectState + { + None, + // connecting between Connect() and OnTransportConnected() + Connecting, + Connected, + // disconnecting between Disconnect() and OnTransportDisconnected() + Disconnecting, + Disconnected + } + + /// NetworkClient with connection to server. + public static partial class NetworkClient + { + // time & value snapshot interpolation are separate. + // -> time is interpolated globally on NetworkClient / NetworkConnection + // -> value is interpolated per-component, i.e. NetworkTransform. + // however, both need to be on the same send interval. + // + // additionally, server & client need to use the same send interval. + // otherwise it's too easy to accidentally cause interpolation issues if + // a component sends with client.interval but interpolates with + // server.interval, etc. + public static int sendRate => NetworkServer.sendRate; + public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms + static double lastSendTime; + + // For security, it is recommended to disconnect a player if a networked + // action triggers an exception\nThis could prevent components being + // accessed in an undefined state, which may be an attack vector for + // exploits. + // + // However, some games may want to allow exceptions in order to not + // interrupt the player's experience. + public static bool exceptionsDisconnect = true; // security by default + + // message handlers by messageId + internal static readonly Dictionary handlers = + new Dictionary(); + + /// All spawned NetworkIdentities by netId. + // client sees OBSERVED spawned ones. + public static readonly Dictionary spawned = + new Dictionary(); + + /// Client's NetworkConnection to server. + public static NetworkConnectionToServer connection { get; internal set; } + + /// True if client is ready (= joined world). + // TODO redundant state. point it to .connection.isReady instead (& test) + // TODO OR remove NetworkConnection.isReady? unless it's used on server + // + // TODO maybe ClientState.Connected/Ready/AddedPlayer/etc.? + // way better for security if we can check states in callbacks + public static bool ready; + + /// NetworkIdentity of the localPlayer + public static NetworkIdentity localPlayer { get; internal set; } + + // NetworkClient state + internal static ConnectState connectState = ConnectState.None; + + /// active is true while a client is connecting/connected either as standalone or as host client. + // (= while the network is active) + public static bool active => connectState == ConnectState.Connecting || + connectState == ConnectState.Connected; + + /// active is true while the client is connected in host mode. + // naming consistent with NetworkServer.activeHost. + public static bool activeHost => connection is LocalConnectionToServer; + + /// Check if client is connecting (before connected). + public static bool isConnecting => connectState == ConnectState.Connecting; + + /// Check if client is connected (after connecting). + public static bool isConnected => connectState == ConnectState.Connected; + + // OnConnected / OnDisconnected used to be NetworkMessages that were + // invoked. this introduced a bug where external clients could send + // Connected/Disconnected messages over the network causing undefined + // behaviour. + // => public so that custom NetworkManagers can hook into it + public static Action OnConnectedEvent; + public static Action OnDisconnectedEvent; + public static Action OnErrorEvent; + public static Action OnTransportExceptionEvent; + + /// Registered spawnable prefabs by assetId. + public static readonly Dictionary prefabs = + new Dictionary(); + + // custom spawn / unspawn handlers by assetId. + // useful to support prefab pooling etc.: + // https://mirror-networking.gitbook.io/docs/guides/gameobjects/custom-spawnfunctions + internal static readonly Dictionary spawnHandlers = + new Dictionary(); + internal static readonly Dictionary unspawnHandlers = + new Dictionary(); + + // spawning + // internal for tests + internal static bool isSpawnFinished; + + // Disabled scene objects that can be spawned again, by sceneId. + internal static readonly Dictionary spawnableObjects = + new Dictionary(); + + internal static Unbatcher unbatcher = new Unbatcher(); + + // interest management component (optional) + // only needed for SetHostVisibility + public static InterestManagementBase aoi; + + // scene loading + public static bool isLoadingScene; + + // connection quality + // this is set by a virtual function in NetworkManager, + // which allows users to overwrite it with their own estimations. + public static ConnectionQuality connectionQuality = ConnectionQuality.ESTIMATING; + public static ConnectionQuality lastConnectionQuality = ConnectionQuality.ESTIMATING; + public static ConnectionQualityMethod connectionQualityMethod = ConnectionQualityMethod.Simple; + public static float connectionQualityInterval = 3; + static double lastConnectionQualityUpdate; + + /// + /// Invoked when connection quality changes. + /// First argument is the old quality, second argument is the new quality. + /// + public static event Action onConnectionQualityChanged; + + // initialization ////////////////////////////////////////////////////// + static void AddTransportHandlers() + { + // community Transports may forget to call OnDisconnected. + // which could cause handlers to be added twice with +=. + // ensure we always clear the old ones first. + // fixes: https://github.com/vis2k/Mirror/issues/3152 + RemoveTransportHandlers(); + + // += so that other systems can also hook into it (i.e. statistics) + Transport.active.OnClientConnected += OnTransportConnected; + Transport.active.OnClientDataReceived += OnTransportData; + Transport.active.OnClientDisconnected += OnTransportDisconnected; + Transport.active.OnClientError += OnTransportError; + Transport.active.OnClientTransportException += OnTransportException; + } + + static void RemoveTransportHandlers() + { + // -= so that other systems can also hook into it (i.e. statistics) + Transport.active.OnClientConnected -= OnTransportConnected; + Transport.active.OnClientDataReceived -= OnTransportData; + Transport.active.OnClientDisconnected -= OnTransportDisconnected; + Transport.active.OnClientError -= OnTransportError; + Transport.active.OnClientTransportException -= OnTransportException; + } + + // connect ///////////////////////////////////////////////////////////// + // initialize is called before every connect + static void Initialize(bool hostMode) + { + // safety: ensure Weaving succeded. + // if it silently failed, we would get lots of 'writer not found' + // and other random errors at runtime instead. this is cleaner. + if (!WeaverFuse.Weaved()) + { + // if it failed, throw an exception to early exit all Connect calls. + throw new Exception("NetworkClient won't start because Weaving failed or didn't run."); + } + + // Debug.Log($"Client Connect: {address}"); + Debug.Assert(Transport.active != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.active' first"); + + // reset unbatcher in case any batches from last session remain. + // need to do this in Initialize() so it runs for the host as well. + // fixes host mode scene transition receiving data from previous scene. + // credits: BigBoxVR + unbatcher = new Unbatcher(); + + // reset time interpolation on every new connect. + // ensures last sessions' state is cleared before starting again. + InitTimeInterpolation(); + + RegisterMessageHandlers(hostMode); + Transport.active.enabled = true; + } + + /// Connect client to a NetworkServer by address. + public static void Connect(string address) + { + Initialize(false); + + AddTransportHandlers(); + connectState = ConnectState.Connecting; + Transport.active.ClientConnect(address); + connection = new NetworkConnectionToServer(); + } + + /// Connect client to a NetworkServer by Uri. + public static void Connect(Uri uri) + { + Initialize(false); + + AddTransportHandlers(); + connectState = ConnectState.Connecting; + Transport.active.ClientConnect(uri); + connection = new NetworkConnectionToServer(); + } + + // TODO why are there two connect host methods? + // called from NetworkManager.FinishStartHost() + public static void ConnectHost() + { + Initialize(true); + connectState = ConnectState.Connected; + HostMode.SetupConnections(); + } + + // disconnect ////////////////////////////////////////////////////////// + /// Disconnect from server. + public static void Disconnect() + { + // only if connected or connecting. + // don't disconnect() again if already in the process of + // disconnecting or fully disconnected. + if (connectState != ConnectState.Connecting && + connectState != ConnectState.Connected) + return; + + // we are disconnecting until OnTransportDisconnected is called. + // setting state to Disconnected would stop OnTransportDisconnected + // from calling cleanup code because it would think we are already + // disconnected fully. + // TODO move to 'cleanup' code below if safe + connectState = ConnectState.Disconnecting; + ready = false; + + // call Disconnect on the NetworkConnection + connection?.Disconnect(); + + // IMPORTANT: do NOT clear connection here yet. + // we still need it in OnTransportDisconnected for callbacks. + // connection = null; + } + + // transport events //////////////////////////////////////////////////// + // called by Transport + static void OnTransportConnected() + { + if (connection != null) + { + // reset network time stats + NetworkTime.ResetStatics(); + + // the handler may want to send messages to the client + // thus we should set the connected state before calling the handler + connectState = ConnectState.Connected; + // ping right away after connecting so client gets new time asap + NetworkTime.SendPing(); + OnConnectedEvent?.Invoke(); + } + else Debug.LogError("Skipped Connect message handling because connection is null."); + } + + // helper function + static bool UnpackAndInvoke(NetworkReader reader, int channelId) + { + if (NetworkMessages.UnpackId(reader, out ushort msgType)) + { + // try to invoke the handler for that message + if (handlers.TryGetValue(msgType, out NetworkMessageDelegate handler)) + { + handler.Invoke(connection, reader, channelId); + + // message handler may disconnect client, making connection = null + // therefore must check for null to avoid NRE. + if (connection != null) + connection.lastMessageTime = Time.time; + + return true; + } + else + { + // message in a batch are NOT length prefixed to save bandwidth. + // every message needs to be handled and read until the end. + // otherwise it would overlap into the next message. + // => need to warn and disconnect to avoid undefined behaviour. + // => WARNING, not error. can happen if attacker sends random data. + Debug.LogWarning($"Unknown message id: {msgType}. This can happen if no handler was registered for this message."); + // simply return false. caller is responsible for disconnecting. + //connection.Disconnect(); + return false; + } + } + else + { + // => WARNING, not error. can happen if attacker sends random data. + Debug.LogWarning("Invalid message header."); + // simply return false. caller is responsible for disconnecting. + //connection.Disconnect(); + return false; + } + } + + // called by Transport + internal static void OnTransportData(ArraySegment data, int channelId) + { + if (connection != null) + { + // server might batch multiple messages into one packet. + // feed it to the Unbatcher. + // NOTE: we don't need to associate a channelId because we + // always process all messages in the batch. + if (!unbatcher.AddBatch(data)) + { + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: failed to add batch, disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkClient: failed to add batch."); + + return; + } + + // process all messages in the batch. + // only while NOT loading a scene. + // if we get a scene change message, then we need to stop + // processing. otherwise we might apply them to the old scene. + // => fixes https://github.com/vis2k/Mirror/issues/2651 + // + // NOTE: is scene starts loading, then the rest of the batch + // would only be processed when OnTransportData is called + // the next time. + // => consider moving processing to NetworkEarlyUpdate. + while (!isLoadingScene && + unbatcher.GetNextMessage(out ArraySegment message, out double remoteTimestamp)) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message)) + { + // enough to read at least header size? + if (reader.Remaining >= NetworkMessages.IdSize) + { + // make remoteTimeStamp available to the user + connection.remoteTimeStamp = remoteTimestamp; + + // handle message + if (!UnpackAndInvoke(reader, channelId)) + { + // warn, disconnect and return if failed + // -> warning because attackers might send random data + // -> messages in a batch aren't length prefixed. + // failing to read one would cause undefined + // behaviour for every message afterwards. + // so we need to disconnect. + // -> return to avoid the below unbatches.count error. + // we already disconnected and handled it. + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: failed to unpack and invoke message. Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkClient: failed to unpack and invoke message."); + + return; + } + } + // otherwise disconnect + else + { + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkClient: received Message was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning("NetworkClient: received Message was too short (messages should start with message id)"); + return; + } + } + } + + // if we weren't interrupted by a scene change, + // then all batched messages should have been processed now. + // if not, we need to log an error to avoid debugging hell. + // otherwise batches would silently grow. + // we need to log an error to avoid debugging hell. + // + // EXAMPLE: https://github.com/vis2k/Mirror/issues/2882 + // -> UnpackAndInvoke silently returned because no handler for id + // -> Reader would never be read past the end + // -> Batch would never be retired because end is never reached + // + // NOTE: prefixing every message in a batch with a length would + // avoid ever not reading to the end. for extra bandwidth. + // + // IMPORTANT: always keep this check to detect memory leaks. + // this took half a day to debug last time. + if (!isLoadingScene && unbatcher.BatchesCount > 0) + { + Debug.LogError($"Still had {unbatcher.BatchesCount} batches remaining after processing, even though processing was not interrupted by a scene change. This should never happen, as it would cause ever growing batches.\nPossible reasons:\n* A message didn't deserialize as much as it serialized\n*There was no message handler for a message id, so the reader wasn't read until the end."); + } + } + else Debug.LogError("Skipped Data message handling because connection is null."); + } + + // called by Transport + // IMPORTANT: often times when disconnecting, we call this from Mirror + // too because we want to remove the connection and handle + // the disconnect immediately. + // => which is fine as long as we guarantee it only runs once + // => which we do by setting the state to Disconnected! + internal static void OnTransportDisconnected() + { + // StopClient called from user code triggers Disconnected event + // from transport which calls StopClient again, so check here + // and short circuit running the Shutdown process twice. + if (connectState == ConnectState.Disconnected) return; + + // Raise the event before changing ConnectState + // because 'active' depends on this during shutdown + // + // previously OnDisconnected was only invoked if connection != null. + // however, if DNS resolve fails in Transport.Connect(), + // OnDisconnected would never be called because 'connection' is only + // created after the Transport.Connect() call. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3365 + OnDisconnectedEvent?.Invoke(); + + connectState = ConnectState.Disconnected; + ready = false; + snapshots.Clear(); + localTimeline = 0; + + // now that everything was handled, clear the connection. + // previously this was done in Disconnect() already, but we still + // need it for the above OnDisconnectedEvent. + connection?.Cleanup(); + connection = null; + + // transport handlers are only added when connecting. + // so only remove when actually disconnecting. + RemoveTransportHandlers(); + } + + // transport errors are forwarded to high level + static void OnTransportError(TransportError error, string reason) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Client Transport Error: {error}: {reason}. This is fine."); + OnErrorEvent?.Invoke(error, reason); + } + + static void OnTransportException(Exception exception) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Client Transport Exception: {exception}. This is fine."); + OnTransportExceptionEvent?.Invoke(exception); + } + + // send //////////////////////////////////////////////////////////////// + /// Send a NetworkMessage to the server over the given channel. + public static void Send(T message, int channelId = Channels.Reliable) + where T : struct, NetworkMessage + { + if (connection != null) + { + if (connectState == ConnectState.Connected) + { + connection.Send(message, channelId); + } + else Debug.LogError("NetworkClient Send when not connected to a server"); + } + else Debug.LogError("NetworkClient Send with no connection"); + } + + // message handlers //////////////////////////////////////////////////// + internal static void RegisterMessageHandlers(bool hostMode) + { + // host mode client / remote client react to some messages differently. + // but we still need to add handlers for all of them to avoid + // 'message id not found' errors. + if (hostMode) + { + // host mode doesn't need destroy messages (see NetworkServer::UnSpawnInternal) + RegisterHandler(_ => { }); + RegisterHandler(OnHostClientObjectHide); + RegisterHandler(_ => { }, false); + RegisterHandler(OnHostClientSpawn); + // host mode doesn't need spawning + RegisterHandler(_ => { }); + // host mode doesn't need spawning + RegisterHandler(_ => { }); + // host mode doesn't need state updates + RegisterHandler(_ => { }); + } + else + { + RegisterHandler(OnObjectDestroy); + RegisterHandler(OnObjectHide); + RegisterHandler(NetworkTime.OnClientPong, false); + RegisterHandler(NetworkTime.OnClientPing, false); + RegisterHandler(OnSpawn); + RegisterHandler(OnObjectSpawnStarted); + RegisterHandler(OnObjectSpawnFinished); + RegisterHandler(OnEntityStateMessage); + } + + // These handlers are the same for host and remote clients + RegisterHandler(OnTimeSnapshotMessage, false); // unreliable may arrive before reliable authority went through + RegisterHandler(OnChangeOwner); + RegisterHandler(OnRPCMessage); + } + + /// Register a handler for a message type T. Most should require authentication. + public static void RegisterHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + if (handlers.ContainsKey(msgType)) + { + Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); + } + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + void HandlerWrapped(NetworkConnection _, T value) => handler(value); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + /// Register a handler for a message type T. Most should require authentication. + // This version passes channelId to the handler. + public static void RegisterHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + if (handlers.ContainsKey(msgType)) + { + Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); + } + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + void HandlerWrapped(NetworkConnection _, T value, int channelId) => handler(value, channelId); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for a particular message type. Should require authentication by default. + // RegisterHandler throws a warning (as it should) if a handler is assigned twice + // Use of ReplaceHandler makes it clear the user intended to replace the handler + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + void HandlerWrapped(NetworkConnection _, T value) => handler(value); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for a particular message type. Should require authentication by default. This version passes channelId to the handler. + // RegisterHandler throws a warning (as it should) if a handler is assigned twice + // Use of ReplaceHandler makes it clear the user intended to replace the handler + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + // we use the same WrapHandler function for server and client. + // so let's wrap it to ignore the NetworkConnection parameter. + // it's not needed on client. it's always NetworkClient.connection. + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + void HandlerWrapped(NetworkConnection _, T value, int channelId) => handler(value, channelId); + handlers[msgType] = NetworkMessages.WrapHandler((Action)HandlerWrapped, requireAuthentication, exceptionsDisconnect); + } + + /// Unregister a message handler of type T. + public static bool UnregisterHandler() + where T : struct, NetworkMessage + { + // use int to minimize collisions + ushort msgType = NetworkMessageId.Id; + return handlers.Remove(msgType); + } + + // spawnable prefabs /////////////////////////////////////////////////// + /// Find the registered prefab for this asset id. + // Useful for debuggers + public static bool GetPrefab(uint assetId, out GameObject prefab) + { + prefab = null; + return assetId != 0 && + prefabs.TryGetValue(assetId, out prefab) && + prefab != null; + } + + /// Validates Prefab then adds it to prefabs dictionary. + static void RegisterPrefabIdentity(NetworkIdentity prefab) + { + if (prefab.assetId == 0) + { + Debug.LogError($"Can not Register '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); + return; + } + + if (prefab.sceneId != 0) + { + Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); + return; + } + + // disallow child NetworkIdentities. + // TODO likely not necessary anymore due to the new check in + // NetworkIdentity.OnValidate. + NetworkIdentity[] identities = prefab.GetComponentsInChildren(); + if (identities.Length > 1) + { + Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); + } + + if (prefabs.ContainsKey(prefab.assetId)) + { + GameObject existingPrefab = prefabs[prefab.assetId]; + Debug.LogWarning($"Replacing existing prefab with assetId '{prefab.assetId}'. Old prefab '{existingPrefab.name}', New prefab '{prefab.name}'"); + } + + if (spawnHandlers.ContainsKey(prefab.assetId) || unspawnHandlers.ContainsKey(prefab.assetId)) + { + Debug.LogWarning($"Adding prefab '{prefab.name}' with assetId '{prefab.assetId}' when spawnHandlers with same assetId already exists. If you want to use custom spawn handling, then remove the prefab from NetworkManager's registered prefabs first."); + } + + // Debug.Log($"Registering prefab '{prefab.name}' as asset:{prefab.assetId}"); + + prefabs[prefab.assetId] = prefab.gameObject; + } + + /// Register spawnable prefab with custom assetId. + // Note: newAssetId can not be set on GameObjects that already have an assetId + // Note: registering with assetId is useful for assetbundles etc. a lot + // of people use this. + public static void RegisterPrefab(GameObject prefab, uint newAssetId) + { + if (prefab == null) + { + Debug.LogError("Could not register prefab because it was null"); + return; + } + + if (newAssetId == 0) + { + Debug.LogError($"Could not register '{prefab.name}' with new assetId because the new assetId was empty"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + if (identity.assetId != 0 && identity.assetId != newAssetId) + { + Debug.LogError($"Could not register '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}"); + return; + } + + identity.assetId = newAssetId; + + RegisterPrefabIdentity(identity); + } + + /// Register spawnable prefab. + public static void RegisterPrefab(GameObject prefab) + { + if (prefab == null) + { + Debug.LogError("Could not register prefab because it was null"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + RegisterPrefabIdentity(identity); + } + + /// Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers. + // Note: newAssetId can not be set on GameObjects that already have an assetId + // Note: registering with assetId is useful for assetbundles etc. a lot + // of people use this. + // TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate? + public static void RegisterPrefab(GameObject prefab, uint newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + // We need this check here because we don't want a null handler in the lambda expression below + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {newAssetId}"); + return; + } + + RegisterPrefab(prefab, newAssetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); + } + + /// Register a spawnable prefab with custom spawn/unspawn handlers. + // TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate? + public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + if (prefab == null) + { + Debug.LogError("Could not register handler for prefab because the prefab was null"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + if (identity.sceneId != 0) + { + Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); + return; + } + + if (identity.assetId == 0) + { + Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); + return; + } + + // We need this check here because we don't want a null handler in the lambda expression below + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {identity.assetId}"); + return; + } + + RegisterPrefab(prefab, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); + } + + /// Register a spawnable prefab with custom assetId and custom spawn/unspawn handlers. + // Note: newAssetId can not be set on GameObjects that already have an assetId + // Note: registering with assetId is useful for assetbundles etc. a lot + // of people use this. + // TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate? + public static void RegisterPrefab(GameObject prefab, uint newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + if (newAssetId == 0) + { + Debug.LogError($"Could not register handler for '{prefab.name}' with new assetId because the new assetId was empty"); + return; + } + + if (prefab == null) + { + Debug.LogError("Could not register handler for prefab because the prefab was null"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + if (identity.assetId != 0 && identity.assetId != newAssetId) + { + Debug.LogError($"Could not register Handler for '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}"); + return; + } + + if (identity.sceneId != 0) + { + Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); + return; + } + + identity.assetId = newAssetId; + uint assetId = identity.assetId; + + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {assetId}"); + return; + } + + if (unspawnHandler == null) + { + Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}"); + return; + } + + if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) + { + Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'"); + } + + if (prefabs.ContainsKey(assetId)) + { + // this is error because SpawnPrefab checks prefabs before handler + Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler"); + } + + NetworkIdentity[] identities = prefab.GetComponentsInChildren(); + if (identities.Length > 1) + { + Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); + } + + //Debug.Log($"Registering custom prefab {prefab.name} as asset:{assetId} {spawnHandler.GetMethodName()}/{unspawnHandler.GetMethodName()}"); + + spawnHandlers[assetId] = spawnHandler; + unspawnHandlers[assetId] = unspawnHandler; + } + + /// Register a spawnable prefab with custom spawn/unspawn handlers. + // TODO why do we have one with SpawnDelegate and one with SpawnHandlerDelegate? + public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + if (prefab == null) + { + Debug.LogError("Could not register handler for prefab because the prefab was null"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not register handler for '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + if (identity.sceneId != 0) + { + Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene."); + return; + } + + uint assetId = identity.assetId; + + if (assetId == 0) + { + Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead"); + return; + } + + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {assetId}"); + return; + } + + if (unspawnHandler == null) + { + Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}"); + return; + } + + if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) + { + Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'"); + } + + if (prefabs.ContainsKey(assetId)) + { + // this is error because SpawnPrefab checks prefabs before handler + Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler"); + } + + NetworkIdentity[] identities = prefab.GetComponentsInChildren(); + if (identities.Length > 1) + { + Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object."); + } + + //Debug.Log($"Registering custom prefab {prefab.name} as asset:{assetId} {spawnHandler.GetMethodName()}/{unspawnHandler.GetMethodName()}"); + + spawnHandlers[assetId] = spawnHandler; + unspawnHandlers[assetId] = unspawnHandler; + } + + /// Removes a registered spawn prefab that was setup with NetworkClient.RegisterPrefab. + public static void UnregisterPrefab(GameObject prefab) + { + if (prefab == null) + { + Debug.LogError("Could not unregister prefab because it was null"); + return; + } + + if (!prefab.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Could not unregister '{prefab.name}' since it contains no NetworkIdentity component"); + return; + } + + uint assetId = identity.assetId; + + prefabs.Remove(assetId); + spawnHandlers.Remove(assetId); + unspawnHandlers.Remove(assetId); + } + + // spawn handlers ////////////////////////////////////////////////////// + /// This is an advanced spawning function that registers a custom assetId with the spawning system. + // This can be used to register custom spawning methods for an assetId - + // instead of the usual method of registering spawning methods for a + // prefab. This should be used when no prefab exists for the spawned + // objects - such as when they are constructed dynamically at runtime + // from configuration data. + public static void RegisterSpawnHandler(uint assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + // We need this check here because we don't want a null handler in the lambda expression below + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {assetId}"); + return; + } + + RegisterSpawnHandler(assetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler); + } + + /// This is an advanced spawning function that registers a custom assetId with the spawning system. + // This can be used to register custom spawning methods for an assetId - + // instead of the usual method of registering spawning methods for a + // prefab. This should be used when no prefab exists for the spawned + // objects - such as when they are constructed dynamically at runtime + // from configuration data. + public static void RegisterSpawnHandler(uint assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler) + { + if (spawnHandler == null) + { + Debug.LogError($"Can not Register null SpawnHandler for {assetId}"); + return; + } + + if (unspawnHandler == null) + { + Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}"); + return; + } + + if (assetId == 0) + { + Debug.LogError("Can not Register SpawnHandler for empty assetId"); + return; + } + + if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId)) + { + Debug.LogWarning($"Replacing existing spawnHandlers for {assetId}"); + } + + if (prefabs.ContainsKey(assetId)) + { + // this is error because SpawnPrefab checks prefabs before handler + Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}'"); + } + + // Debug.Log("RegisterSpawnHandler asset {assetId} {spawnHandler.GetMethodName()}/{unspawnHandler.GetMethodName()}"); + + spawnHandlers[assetId] = spawnHandler; + unspawnHandlers[assetId] = unspawnHandler; + } + + /// Removes a registered spawn handler function that was registered with NetworkClient.RegisterHandler(). + public static void UnregisterSpawnHandler(uint assetId) + { + spawnHandlers.Remove(assetId); + unspawnHandlers.Remove(assetId); + } + + /// This clears the registered spawn prefabs and spawn handler functions for this client. + public static void ClearSpawners() + { + prefabs.Clear(); + spawnHandlers.Clear(); + unspawnHandlers.Clear(); + } + + internal static bool InvokeUnSpawnHandler(uint assetId, GameObject obj) + { + if (unspawnHandlers.TryGetValue(assetId, out UnSpawnDelegate handler) && handler != null) + { + handler(obj); + return true; + } + return false; + } + + // ready /////////////////////////////////////////////////////////////// + /// Sends Ready message to server, indicating that we loaded the scene, ready to enter the game. + // This could be for example when a client enters an ongoing game and + // has finished loading the current scene. The server should respond to + // the SYSTEM_READY event with an appropriate handler which instantiates + // the players object for example. + public static bool Ready() + { + // Debug.Log($"NetworkClient.Ready() called with connection {conn}"); + if (ready) + { + Debug.LogError("NetworkClient is already ready. It shouldn't be called twice."); + return false; + } + + // need a valid connection to become ready + if (connection == null) + { + Debug.LogError("Ready() called with invalid connection object: conn=null"); + return false; + } + + // Set these before sending the ReadyMessage, otherwise host client + // will fail in InternalAddPlayer with null readyConnection. + // TODO this is redundant. have one source of truth for .ready + ready = true; + connection.isReady = true; + + // Tell server we're ready to have a player object spawned + connection.Send(new ReadyMessage()); + return true; + } + + // add player ////////////////////////////////////////////////////////// + // called from message handler for Owner message + internal static void InternalAddPlayer(NetworkIdentity identity) + { + //Debug.Log("NetworkClient.InternalAddPlayer"); + + // NOTE: It can be "normal" when changing scenes for the player to be destroyed and recreated. + // But, the player structures are not cleaned up, we'll just replace the old player + localPlayer = identity; + + // NOTE: we DONT need to set isClient=true here, because OnStartClient + // is called before OnStartLocalPlayer, hence it's already set. + // localPlayer.isClient = true; + + // TODO this check might not be necessary + //if (readyConnection != null) + if (ready && connection != null) + { + connection.identity = identity; + } + else Debug.LogWarning("NetworkClient can't AddPlayer before being ready. Please call NetworkClient.Ready() first. Clients are considered ready after joining the game world."); + } + + /// Sends AddPlayer message to the server, indicating that we want to join the world. + public static bool AddPlayer() + { + // ensure valid ready connection + if (connection == null) + { + Debug.LogError("AddPlayer requires a valid NetworkClient.connection."); + return false; + } + + // UNET checked 'if readyConnection != null'. + // in other words, we need a connection and we need to be ready. + if (!ready) + { + Debug.LogError("AddPlayer requires a ready NetworkClient."); + return false; + } + + if (connection.identity != null) + { + Debug.LogError("NetworkClient.AddPlayer: a PlayerController was already added. Did you call AddPlayer twice?"); + return false; + } + + // Debug.Log($"NetworkClient.AddPlayer() called with connection {readyConnection}"); + connection.Send(new AddPlayerMessage()); + return true; + } + + // spawning //////////////////////////////////////////////////////////// + internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage message) + { + // add to spawned first because DeserializeClient may need it for SyncVars + spawned[message.netId] = identity; + + if (message.assetId != 0) + identity.assetId = message.assetId; + + if (!identity.gameObject.activeSelf) + identity.gameObject.SetActive(true); + + // apply local values for VR support + identity.transform.localPosition = message.position; + identity.transform.localRotation = message.rotation; + identity.transform.localScale = message.scale; + + // configure flags + // the below DeserializeClient call invokes SyncVarHooks. + // flags always need to be initialized before that. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3259 + identity.netId = message.netId; + identity.isOwned = message.isOwner; + + if (identity.isOwned) + connection?.owned.Add(identity); + + if (message.isLocalPlayer) + InternalAddPlayer(identity); + + // configure isClient/isLocalPlayer flags. + // => after InternalAddPlayer. can't initialize .isLocalPlayer + // before InternalAddPlayer sets .localPlayer + // => before DeserializeClient, otherwise SyncVar hooks wouldn't + // have isClient/isLocalPlayer set yet. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3259 + InitializeIdentityFlags(identity); + + // deserialize components if any payload + // (Count is 0 if there were no components) + if (message.payload.Count > 0) + { + using (NetworkReaderPooled payloadReader = NetworkReaderPool.Get(message.payload)) + { + identity.DeserializeClient(payloadReader, true); + } + } + + // the initial spawn with OnObjectSpawnStarted/Finished calls all + // object's OnStartClient/OnStartLocalPlayer after they were all + // spawned. + // this only happens once though. + // for all future spawns, we need to call OnStartClient/LocalPlayer + // here immediately since there won't be another OnObjectSpawnFinished. + if (isSpawnFinished) + { + InvokeIdentityCallbacks(identity); + } + } + + // Finds Existing Object with NetId or spawns a new one using AssetId or sceneId + internal static bool FindOrSpawnObject(SpawnMessage message, out NetworkIdentity identity) + { + // was the object already spawned? + identity = GetExistingObject(message.netId); + + // if found, return early + if (identity != null) + { + return true; + } + + if (message.assetId == 0 && message.sceneId == 0) + { + Debug.LogError($"OnSpawn message with netId '{message.netId}' has no AssetId or sceneId"); + return false; + } + + identity = message.sceneId == 0 ? SpawnPrefab(message) : SpawnSceneObject(message.sceneId); + + if (identity == null) + { + Debug.LogError($"Could not spawn assetId={message.assetId} scene={message.sceneId:X} netId={message.netId}"); + return false; + } + + return true; + } + + static NetworkIdentity GetExistingObject(uint netid) + { + spawned.TryGetValue(netid, out NetworkIdentity identity); + return identity; + } + + static NetworkIdentity SpawnPrefab(SpawnMessage message) + { + // custom spawn handler for this prefab? (for prefab pools etc.) + // + // IMPORTANT: look for spawn handlers BEFORE looking for registered + // prefabs. Unspawning also looks for unspawn handlers + // before falling back to regular Destroy. this needs to + // be consistent. + // https://github.com/vis2k/Mirror/issues/2705 + if (spawnHandlers.TryGetValue(message.assetId, out SpawnHandlerDelegate handler)) + { + GameObject obj = handler(message); + if (obj == null) + { + Debug.LogError($"Spawn Handler returned null, Handler assetId '{message.assetId}'"); + return null; + } + + if (!obj.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{message.assetId}'"); + return null; + } + + return identity; + } + + // otherwise look in NetworkManager registered prefabs + if (GetPrefab(message.assetId, out GameObject prefab)) + { + GameObject obj = GameObject.Instantiate(prefab, message.position, message.rotation); + //Debug.Log($"Client spawn handler instantiating [netId{message.netId} asset ID:{message.assetId} pos:{message.position} rotation:{message.rotation}]"); + return obj.GetComponent(); + } + + Debug.LogError($"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={message.assetId} netId={message.netId}"); + return null; + } + + static NetworkIdentity SpawnSceneObject(ulong sceneId) + { + NetworkIdentity identity = GetAndRemoveSceneObject(sceneId); + if (identity == null) + { + Debug.LogError($"Spawn scene object not found for {sceneId:X}. Make sure that client and server use exactly the same project. This only happens if the hierarchy gets out of sync."); + + // dump the whole spawnable objects dict for easier debugging + //foreach (KeyValuePair kvp in spawnableObjects) + // Debug.Log($"Spawnable: SceneId={kvp.Key:X} name={kvp.Value.name}"); + } + //else Debug.Log($"Client spawn for [netId:{msg.netId}] [sceneId:{msg.sceneId:X}] obj:{identity}"); + return identity; + } + + static NetworkIdentity GetAndRemoveSceneObject(ulong sceneId) + { + if (spawnableObjects.TryGetValue(sceneId, out NetworkIdentity identity)) + { + spawnableObjects.Remove(sceneId); + return identity; + } + return null; + } + + /// Call this after loading/unloading a scene in the client after connection to register the spawnable objects + public static void PrepareToSpawnSceneObjects() + { + // remove existing items, they will be re-added below + spawnableObjects.Clear(); + + // finds all NetworkIdentity currently loaded by unity (includes disabled objects) + NetworkIdentity[] allIdentities = Resources.FindObjectsOfTypeAll(); + foreach (NetworkIdentity identity in allIdentities) + { + // add all unspawned NetworkIdentities to spawnable objects + // need to check netId to make sure object is not spawned + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3541 + // PrepareToSpawnSceneObjects may be called multiple times in case + // the ObjectSpawnStarted message is received multiple times. + if (Utils.IsSceneObject(identity) && + identity.netId == 0) + { + if (spawnableObjects.TryGetValue(identity.sceneId, out NetworkIdentity existingIdentity)) + { + string msg = $"NetworkClient: Duplicate sceneId {identity.sceneId} detected on {identity.gameObject.name} and {existingIdentity.gameObject.name}\n" + + $"This can happen if a networked object is persisted in DontDestroyOnLoad through loading / changing to the scene where it originated,\n" + + $"otherwise you may need to open and re-save the {identity.gameObject.scene} to reset scene id's."; + Debug.LogWarning(msg, identity.gameObject); + } + else + { + spawnableObjects.Add(identity.sceneId, identity); + } + } + } + } + + internal static void OnObjectSpawnStarted(ObjectSpawnStartedMessage _) + { + // Debug.Log("SpawnStarted"); + PrepareToSpawnSceneObjects(); + pendingSpawns.Clear(); + isSpawnFinished = false; + } + + static readonly Dictionary pendingSpawns = new Dictionary(); + + internal static void OnObjectSpawnFinished(ObjectSpawnFinishedMessage _) + { + // paul: Initialize the objects in the same order as they were + // initialized in the server. This is important if spawned objects + // use data from scene objects + foreach (NetworkIdentity identity in spawned.Values.OrderBy(uv => uv.netId)) + { + // NetworkIdentities should always be removed from .spawned when + // they are destroyed. for safety, let's double check here. + if (identity != null) + { + // We may have deferred ApplySpawnPayload in OnSpawn + // to avoid cross-reference race conditions with SyncVars. + // Apply payload before invoking OnStartClient etc. callbacks + // so that all data is there when they are invoked. + // Note that Interest Management may not have updated spawned + // dictionary yet, so not all identities may be in pendingSpawns. + // Generally that's user error in their code, so we don't throw + // a warning here, but keep the warning code for debugging if needed. + if (pendingSpawns.TryGetValue(identity, out SpawnMessage message)) + ApplySpawnPayload(identity, message); + //else + // Debug.LogWarning($"Expected pendingSpawns to contain {identity}: {identity.netId} but didn't"); + + BootstrapIdentity(identity); + } + else Debug.LogWarning("Found null entry in NetworkClient.spawned. This is unexpected. Was the NetworkIdentity not destroyed properly?"); + } + + pendingSpawns.Clear(); + isSpawnFinished = true; + } + + // host mode callbacks ///////////////////////////////////////////////// + static void OnHostClientObjectHide(ObjectHideMessage message) + { + //Debug.Log($"ClientScene::OnLocalObjectObjHide netId:{message.netId}"); + if (spawned.TryGetValue(message.netId, out NetworkIdentity identity) && + identity != null) + { + if (aoi != null) + aoi.SetHostVisibility(identity, false); + } + } + + internal static void OnHostClientSpawn(SpawnMessage message) + { + // on host mode, the object already exist in NetworkServer.spawned. + // simply add it to NetworkClient.spawned too. + if (NetworkServer.spawned.TryGetValue(message.netId, out NetworkIdentity identity) && identity != null) + { + spawned[message.netId] = identity; + if (message.isOwner) connection.owned.Add(identity); + + // now do the actual 'spawning' on host mode + if (message.isLocalPlayer) + InternalAddPlayer(identity); + + // set visibility before invoking OnStartClient etc. callbacks + if (aoi != null) + aoi.SetHostVisibility(identity, true); + + identity.isOwned = message.isOwner; + BootstrapIdentity(identity); + } + } + + // configure flags & invoke callbacks + static void BootstrapIdentity(NetworkIdentity identity) + { + InitializeIdentityFlags(identity); + InvokeIdentityCallbacks(identity); + } + + // set up NetworkIdentity flags on the client. + // needs to be separate from invoking callbacks. + // cleaner, and some places need to set flags first. + static void InitializeIdentityFlags(NetworkIdentity identity) + { + // initialize flags before invoking callbacks. + // this way isClient/isLocalPlayer is correct during callbacks. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3362 + identity.isClient = true; + identity.isLocalPlayer = localPlayer == identity; + + // .connectionToServer is only available for local players. + // set it here, before invoking any callbacks. + // this way it's available in _all_ callbacks. + if (identity.isLocalPlayer) + identity.connectionToServer = connection; + } + + // invoke NetworkIdentity callbacks on the client. + // needs to be separate from configuring flags. + // cleaner, and some places need to set flags first. + static void InvokeIdentityCallbacks(NetworkIdentity identity) + { + // invoke OnStartClient + identity.OnStartClient(); + + // invoke OnStartAuthority + identity.NotifyAuthority(); + + // invoke OnStartLocalPlayer + if (identity.isLocalPlayer) + identity.OnStartLocalPlayer(); + } + + // client-only mode callbacks ////////////////////////////////////////// + static void OnEntityStateMessage(EntityStateMessage message) + { + // Debug.Log($"NetworkClient.OnUpdateVarsMessage {msg.netId}"); + if (spawned.TryGetValue(message.netId, out NetworkIdentity identity) && identity != null) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload)) + identity.DeserializeClient(reader, false); + } + else Debug.LogWarning($"Did not find target for sync message for {message.netId}. Were all prefabs added to the NetworkManager's spawnable list?\nNote: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); + } + + static void OnRPCMessage(RpcMessage message) + { + // Debug.Log($"NetworkClient.OnRPCMessage hash:{message.functionHash} netId:{message.netId}"); + if (spawned.TryGetValue(message.netId, out NetworkIdentity identity)) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload)) + identity.HandleRemoteCall(message.componentIndex, message.functionHash, RemoteCallType.ClientRpc, reader); + } + // Rpcs often can't be applied if interest management unspawned them + } + + static void OnObjectHide(ObjectHideMessage message) => DestroyObject(message.netId); + + internal static void OnObjectDestroy(ObjectDestroyMessage message) => DestroyObject(message.netId); + + internal static void OnSpawn(SpawnMessage message) + { + // Debug.Log($"Client spawn handler instantiating netId={msg.netId} assetID={msg.assetId} sceneId={msg.sceneId:X} pos={msg.position}"); + if (FindOrSpawnObject(message, out NetworkIdentity identity)) + { + if (isSpawnFinished) + { + ApplySpawnPayload(identity, message); + } + else + { + // Defer ApplySpawnPayload until OnObjectSpawnFinished + // add to spawned because later when we ApplySpawnPayload + // there may be SyncVars that cross-reference other objects + + // When deferring ApplySpawnPayload via pendingSpawns until OnObjectSpawnFinished, + // simply copying the SpawnMessage struct isn't sufficient. The payload is an + // ArraySegment referencing the original buffer received from the server, + // managed by the client's NetworkReaderPooled. This buffer may be recycled or + // reused after OnSpawn but before ApplySpawnPayload, leading to corruption + // (e.g., EndOfStreamException in NetworkReader.ReadBlittable when reading past + // available bytes, as seen with 20+ objects in Benchmark). Deep copying payload + // ensures the data remains intact and independent of the reader's pooled buffer + // lifecycle, preventing corruption during deferred application. + byte[] payloadCopy = new byte[message.payload.Count]; + if (message.payload.Count > 0) + Array.Copy(message.payload.Array, message.payload.Offset, payloadCopy, 0, message.payload.Count); + SpawnMessage messageCopy = new SpawnMessage + { + netId = message.netId, + spawnFlags = message.spawnFlags, // Preserves isOwner and isLocalPlayer via flags + sceneId = message.sceneId, + assetId = message.assetId, + position = message.position, + rotation = message.rotation, + scale = message.scale, + payload = new ArraySegment(payloadCopy) + }; + spawned[message.netId] = identity; + pendingSpawns[identity] = messageCopy; + } + } + } + + internal static void OnChangeOwner(ChangeOwnerMessage message) + { + NetworkIdentity identity = GetExistingObject(message.netId); + + if (identity != null) + ChangeOwner(identity, message); + else + Debug.LogError($"OnChangeOwner: Could not find object with netId {message.netId}"); + } + + // ChangeOwnerMessage contains new 'owned' and new 'localPlayer' + // that we need to apply to the identity. + internal static void ChangeOwner(NetworkIdentity identity, ChangeOwnerMessage message) + { + // local player before, but not anymore? + // call OnStopLocalPlayer before setting new values. + if (identity.isLocalPlayer && !message.isLocalPlayer) + { + identity.OnStopLocalPlayer(); + } + + // set ownership flag (aka authority) + identity.isOwned = message.isOwner; + + // Add / Remove to client's connectionToServer.owned hashset. + if (identity.isOwned) + connection?.owned.Add(identity); + else + connection?.owned.Remove(identity); + + // Call OnStartAuthority / OnStopAuthority + identity.NotifyAuthority(); + + // set localPlayer flag + identity.isLocalPlayer = message.isLocalPlayer; + + // identity is now local player. set our static helper field to it. + if (identity.isLocalPlayer) + { + localPlayer = identity; + identity.connectionToServer = connection; + identity.OnStartLocalPlayer(); + } + // identity's isLocalPlayer was set to false. + // clear our static localPlayer IF (and only IF) it was that one before. + else if (localPlayer == identity) + { + localPlayer = null; + // TODO set .connectionToServer to null for old local player? + // since we set it in the above 'if' case too. + } + } + + // update ////////////////////////////////////////////////////////////// + // NetworkEarlyUpdate called before any Update/FixedUpdate + // (we add this to the UnityEngine in NetworkLoop) + internal static void NetworkEarlyUpdate() + { + // process all incoming messages first before updating the world + if (Transport.active != null) + Transport.active.ClientEarlyUpdate(); + + // time snapshot interpolation + UpdateTimeInterpolation(); + } + + // NetworkLateUpdate called after any Update/FixedUpdate/LateUpdate + // (we add this to the UnityEngine in NetworkLoop) + internal static void NetworkLateUpdate() + { + // broadcast ClientToServer components while active + if (active) + { + // broadcast every sendInterval. + // AccurateInterval to avoid update frequency inaccuracy issues: + // https://github.com/vis2k/Mirror/pull/3153 + // + // for example, host mode server doesn't set .targetFrameRate. + // Broadcast() would be called every tick. + // snapshots might be sent way too often, etc. + // + // during tests, we always call Broadcast() though. + // + // also important for syncInterval=0 components like + // NetworkTransform, so they can sync on same interval as time + // snapshots _but_ not every single tick. + // + // Unity 2019 doesn't have Time.timeAsDouble yet + bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime); + if (!Application.isPlaying || sendIntervalElapsed) + { + Broadcast(); + } + + UpdateConnectionQuality(); + } + + // Connection Quality ////////////////////////////////////////////////// + // uses 'pragmatic' version based on snapshot interpolation by default. + void UpdateConnectionQuality() + { + // only recalculate every few seconds + // we don't want to fire Good->Bad->Good->Bad dozens of times per second. + if (connectionQualityInterval > 0 && NetworkTime.time > lastConnectionQualityUpdate + connectionQualityInterval) + { + lastConnectionQualityUpdate = NetworkTime.time; + + switch (connectionQualityMethod) + { + case ConnectionQualityMethod.Simple: + connectionQuality = ConnectionQualityHeuristics.Simple(NetworkTime.rtt, NetworkTime.rttVariance); + break; + case ConnectionQualityMethod.Pragmatic: + connectionQuality = ConnectionQualityHeuristics.Pragmatic(initialBufferTime, bufferTime); + break; + } + + if (lastConnectionQuality != connectionQuality) + { + // Invoke the event before assigning the new value so + // the event handler can compare old and new values. + onConnectionQualityChanged?.Invoke(lastConnectionQuality, connectionQuality); + lastConnectionQuality = connectionQuality; + } + } + } + + // update connections to flush out messages _after_ broadcast + // local connection? + if (connection is LocalConnectionToServer localConnection) + { + localConnection.Update(); + } + // remote connection? + else if (connection is NetworkConnectionToServer remoteConnection) + { + // only update things while connected + if (active && connectState == ConnectState.Connected) + { + // update NetworkTime + NetworkTime.UpdateClient(); + + // update connection to flush out batched messages + remoteConnection.Update(); + } + } + + // process all outgoing messages after updating the world + if (Transport.active != null) + Transport.active.ClientLateUpdate(); + } + + // broadcast /////////////////////////////////////////////////////////// + // make sure Broadcast() is only called every sendInterval. + // calling it every update() would require too much bandwidth. + static void Broadcast() + { + // joined the world yet? + if (!connection.isReady) return; + + // nothing to do in host mode. server already knows the state. + if (NetworkServer.active) return; + + // send time snapshot every sendInterval. + Send(new TimeSnapshotMessage(), Channels.Unreliable); + + // broadcast client state to server + BroadcastToServer(); + } + + // NetworkServer has BroadcastToConnection. + // NetworkClient has BroadcastToServer. + static void BroadcastToServer() + { + // for each entity that the client owns + foreach (NetworkIdentity identity in connection.owned) + { + // make sure it's not null or destroyed. + // (which can happen if someone uses + // GameObject.Destroy instead of + // NetworkServer.Destroy) + if (identity != null) + { + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // get serialization for this entity viewed by this connection + // (if anything was serialized this time) + identity.SerializeClient(writer); + if (writer.Position > 0) + { + // send state update message + EntityStateMessage message = new EntityStateMessage + { + netId = identity.netId, + payload = writer.ToArraySegment() + }; + Send(message); + } + } + } + // spawned list should have no null entries because we + // always call Remove in OnObjectDestroy everywhere. + // if it does have null then we missed something. + else Debug.LogWarning($"Found 'null' entry in owned list for client. This is unexpected behaviour."); + } + } + + // destroy ///////////////////////////////////////////////////////////// + /// Destroys all networked objects on the client. + // Note: NetworkServer.CleanupNetworkIdentities does the same on server. + public static void DestroyAllClientObjects() + { + // user can modify spawned lists which causes InvalidOperationException + // list can modified either in UnSpawnHandler or in OnDisable/OnDestroy + // we need the Try/Catch so that the rest of the shutdown does not get stopped + try + { + foreach (NetworkIdentity identity in spawned.Values) + { + if (identity != null && identity.gameObject != null) + { + if (identity.isLocalPlayer) + identity.OnStopLocalPlayer(); + + identity.OnStopClient(); + + // NetworkClient.Shutdown calls DestroyAllClientObjects. + // which destroys all objects in NetworkClient.spawned. + // => NC.spawned contains owned & observed objects + // => in host mode, we CAN NOT destroy observed objects. + // => that would destroy them other connection's objects + // on the host server, making them disconnect. + // https://github.com/vis2k/Mirror/issues/2954 + bool hostOwned = identity.connectionToServer is LocalConnectionToServer; + bool shouldDestroy = !identity.isServer || hostOwned; + if (shouldDestroy) + { + bool wasUnspawned = InvokeUnSpawnHandler(identity.assetId, identity.gameObject); + + // unspawned objects should be reset for reuse later. + if (wasUnspawned) + { + identity.ResetState(); + } + // without unspawn handler, we need to disable/destroy. + else + { + // scene objects are reset and disabled. + // they always stay in the scene, we don't destroy them. + if (identity.sceneId != 0) + { + identity.ResetState(); + identity.gameObject.SetActive(false); + } + // spawned objects are destroyed + else + { + GameObject.Destroy(identity.gameObject); + } + } + } + } + } + spawned.Clear(); + connection?.owned.Clear(); + } + catch (InvalidOperationException e) + { + Debug.LogException(e); + Debug.LogError("Could not DestroyAllClientObjects because spawned list was modified during loop, make sure you are not modifying NetworkIdentity.spawned by calling NetworkServer.Destroy or NetworkServer.Spawn in OnDestroy or OnDisable."); + } + } + + static void DestroyObject(uint netId) + { + // Debug.Log($"NetworkClient.OnObjDestroy netId: {netId}"); + if (spawned.TryGetValue(netId, out NetworkIdentity identity) && identity != null) + { + if (identity.isLocalPlayer) + identity.OnStopLocalPlayer(); + + identity.OnStopClient(); + + // custom unspawn handler for this prefab? (for prefab pools etc.) + if (InvokeUnSpawnHandler(identity.assetId, identity.gameObject)) + { + // reset object after user's handler + identity.ResetState(); + } + // otherwise fall back to default Destroy + else if (identity.sceneId == 0) + { + // don't call reset before destroy so that values are still set in OnDestroy + GameObject.Destroy(identity.gameObject); + } + // scene object.. disable it in scene instead of destroying + else + { + identity.gameObject.SetActive(false); + spawnableObjects[identity.sceneId] = identity; + // reset for scene objects + identity.ResetState(); + } + + // remove from dictionary no matter how it is unspawned + connection.owned.Remove(identity); // if any + spawned.Remove(netId); + } + //else Debug.LogWarning($"Did not find target for destroy message for {netId}"); + } + + // shutdown //////////////////////////////////////////////////////////// + /// Shutdown the client. + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + public static void Shutdown() + { + //Debug.Log("Shutting down client."); + + // objects need to be destroyed before spawners are cleared + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3334 + DestroyAllClientObjects(); + + // calls prefabs.Clear(); + // calls spawnHandlers.Clear(); + // calls unspawnHandlers.Clear(); + ClearSpawners(); + + spawned.Clear(); + connection?.owned.Clear(); + handlers.Clear(); + spawnableObjects.Clear(); + + // IMPORTANT: do NOT call NetworkIdentity.ResetStatics() here! + // calling StopClient() in host mode would reset nextNetId to 1, + // causing next connection to have a duplicate netId accidentally. + // => see also: https://github.com/vis2k/Mirror/issues/2954 + //NetworkIdentity.ResetStatics(); + // => instead, reset only the client sided statics. + NetworkIdentity.ResetClientStatics(); + + // disconnect the client connection. + // we do NOT call Transport.Shutdown, because someone only called + // NetworkClient.Shutdown. we can't assume that the server is + // supposed to be shut down too! + if (Transport.active != null) + Transport.active.ClientDisconnect(); + + // reset statics + connectState = ConnectState.None; + connection = null; + localPlayer = null; + ready = false; + isSpawnFinished = false; + isLoadingScene = false; + lastSendTime = 0; + + unbatcher = new Unbatcher(); + + // clear events. someone might have hooked into them before, but + // we don't want to use those hooks after Shutdown anymore. + OnConnectedEvent = null; + OnDisconnectedEvent = null; + OnErrorEvent = null; + OnTransportExceptionEvent = null; + } + + // GUI ///////////////////////////////////////////////////////////////// + // called from NetworkManager to display timeline interpolation status. + // useful to indicate catchup / slowdown / dynamic adjustment etc. + public static void OnGUI() + { + // only if in world + if (!ready) return; + + GUILayout.BeginArea(new Rect(10, 5, 1020, 50)); + + GUILayout.BeginHorizontal("Box"); + GUILayout.Label("Snapshot Interp.:"); + // color while catching up / slowing down + if (localTimescale > 1) GUI.color = Color.green; // green traffic light = go fast + else if (localTimescale < 1) GUI.color = Color.red; // red traffic light = go slow + else GUI.color = Color.white; + GUILayout.Box($"timeline: {localTimeline:F2}"); + GUILayout.Box($"buffer: {snapshots.Count}"); + GUILayout.Box($"DriftEMA: {NetworkClient.driftEma.Value:F2}"); + GUILayout.Box($"DelTimeEMA: {NetworkClient.deliveryTimeEma.Value:F2}"); + GUILayout.Box($"timescale: {localTimescale:F2}"); + GUILayout.Box($"BTM: {NetworkClient.bufferTimeMultiplier:F2}"); // current dynamically adjusted multiplier + GUILayout.Box($"RTT: {NetworkTime.rtt * 1000:F0}ms"); + GUILayout.Box($"PredErrUNADJ: {NetworkTime.predictionErrorUnadjusted * 1000:F0}ms"); + GUILayout.Box($"PredErrADJ: {NetworkTime.predictionErrorAdjusted * 1000:F0}ms"); + GUILayout.EndHorizontal(); + + GUILayout.EndArea(); + } + } +} diff --git a/Assets/Mirror/Core/NetworkClient.cs.meta b/Assets/Mirror/Core/NetworkClient.cs.meta new file mode 100644 index 0000000..33080e4 --- /dev/null +++ b/Assets/Mirror/Core/NetworkClient.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: abe6be14204d94224a3e7cd99dd2ea73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkClient.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs new file mode 100644 index 0000000..2578034 --- /dev/null +++ b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + public static partial class NetworkClient + { + // snapshot interpolation settings ///////////////////////////////////// + // TODO expose the settings to the user later. + // via NetMan or NetworkClientConfig or NetworkClient as component etc. + public static SnapshotInterpolationSettings snapshotSettings = new SnapshotInterpolationSettings(); + + // snapshot interpolation runtime data ///////////////////////////////// + // buffer time is dynamically adjusted. + // store the current multiplier here, without touching the original in settings. + // this way we can easily reset to or compare with original where needed. + public static double bufferTimeMultiplier; + + // original buffer time based on the settings + // dynamically adjusted buffer time based on dynamically adjusted multiplier + public static double initialBufferTime => NetworkServer.sendInterval * snapshotSettings.bufferTimeMultiplier; + public static double bufferTime => NetworkServer.sendInterval * bufferTimeMultiplier; + + // + public static SortedList snapshots = new SortedList(); + + // for smooth interpolation, we need to interpolate along server time. + // any other time (arrival on client, client local time, etc.) is not + // going to give smooth results. + // in other words, this is the remote server's time, but adjusted. + // + // internal for use from NetworkTime. + // double for long running servers, see NetworkTime comments. + internal static double localTimeline; + + // catchup / slowdown adjustments are applied to timescale, + // to be adjusted in every update instead of when receiving messages. + internal static double localTimescale = 1; + + // catchup ///////////////////////////////////////////////////////////// + // we use EMA to average the last second worth of snapshot time diffs. + // manually averaging the last second worth of values with a for loop + // would be the same, but a moving average is faster because we only + // ever add one value. + static ExponentialMovingAverage driftEma; + + // dynamic buffer time adjustment ////////////////////////////////////// + // DEPRECATED 2024-10-08 + [Obsolete("NeworkClient.dynamicAdjustment was moved to NetworkClient.snapshotSettings.dynamicAdjustment")] + public static bool dynamicAdjustment => snapshotSettings.dynamicAdjustment; + // DEPRECATED 2024-10-08 + [Obsolete("NeworkClient.dynamicAdjustmentTolerance was moved to NetworkClient.snapshotSettings.dynamicAdjustmentTolerance")] + public static float dynamicAdjustmentTolerance => snapshotSettings.dynamicAdjustmentTolerance; + // DEPRECATED 2024-10-08 + [Obsolete("NeworkClient.dynamicAdjustment was moved to NetworkClient.snapshotSettings.dynamicAdjustment")] + public static int deliveryTimeEmaDuration => snapshotSettings.deliveryTimeEmaDuration; + + static ExponentialMovingAverage deliveryTimeEma; // average delivery time (standard deviation gives average jitter) + + // OnValidate: see NetworkClient.cs + // add snapshot & initialize client interpolation time if needed + + // initialization called from Awake + static void InitTimeInterpolation() + { + // reset timeline, localTimescale & snapshots from last session (if any) + bufferTimeMultiplier = snapshotSettings.bufferTimeMultiplier; + localTimeline = 0; + localTimescale = 1; + snapshots.Clear(); + + // initialize EMA with 'emaDuration' seconds worth of history. + // 1 second holds 'sendRate' worth of values. + // multiplied by emaDuration gives n-seconds. + driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * snapshotSettings.driftEmaDuration); + deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * snapshotSettings.deliveryTimeEmaDuration); + } + + // server sends TimeSnapshotMessage every sendInterval. + // batching already includes the remoteTimestamp. + // we simply insert it on-message here. + // => only for reliable channel. unreliable would always arrive earlier. + static void OnTimeSnapshotMessage(TimeSnapshotMessage _) + { + // insert another snapshot for snapshot interpolation. + // before calling OnDeserialize so components can use + // NetworkTime.time and NetworkTime.timeStamp. + + // Unity 2019 doesn't have Time.timeAsDouble yet + OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime)); + } + + // see comments at the top of this file + public static void OnTimeSnapshot(TimeSnapshot snap) + { + // Debug.Log($"NetworkClient: OnTimeSnapshot @ {snap.remoteTime:F3}"); + + // (optional) dynamic adjustment + if (snapshotSettings.dynamicAdjustment) + { + // set bufferTime on the fly. + // shows in inspector for easier debugging :) + bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment( + NetworkServer.sendInterval, + deliveryTimeEma.StandardDeviation, + snapshotSettings.dynamicAdjustmentTolerance + ); + } + + // insert into the buffer & initialize / adjust / catchup + SnapshotInterpolation.InsertAndAdjust( + snapshots, + snapshotSettings.bufferLimit, + snap, + ref localTimeline, + ref localTimescale, + NetworkServer.sendInterval, + bufferTime, + snapshotSettings.catchupSpeed, + snapshotSettings.slowdownSpeed, + ref driftEma, + snapshotSettings.catchupNegativeThreshold, + snapshotSettings.catchupPositiveThreshold, + ref deliveryTimeEma); + + // Debug.Log($"inserted TimeSnapshot remote={snap.remoteTime:F2} local={snap.localTime:F2} total={snapshots.Count}"); + } + + // call this from early update, so the timeline is safe to use in update + static void UpdateTimeInterpolation() + { + // only while we have snapshots. + // timeline starts when the first snapshot arrives. + if (snapshots.Count > 0) + { + // progress local timeline. + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 + SnapshotInterpolation.StepTime(Time.unscaledDeltaTime, ref localTimeline, localTimescale); + + // progress local interpolation. + // TimeSnapshot doesn't interpolate anything. + // this is merely to keep removing older snapshots. + SnapshotInterpolation.StepInterpolation(snapshots, localTimeline, out _, out _, out double t); + // Debug.Log($"NetworkClient SnapshotInterpolation @ {localTimeline:F2} t={t:F2}"); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs.meta b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs.meta new file mode 100644 index 0000000..4e836ff --- /dev/null +++ b/Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ad039071a9cc487b9f7831d28bbe8e83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkClient_TimeInterpolation.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkConnection.cs b/Assets/Mirror/Core/NetworkConnection.cs new file mode 100644 index 0000000..1268ca2 --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnection.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + /// Base NetworkConnection class for server-to-client and client-to-server connection. + public abstract class NetworkConnection + { + public const int LocalConnectionId = 0; + + /// Flag that indicates the client has been authenticated. + public bool isAuthenticated; + + /// General purpose object to hold authentication data, character selection, tokens, etc. + public object authenticationData; + + /// A server connection is ready after joining the game world. + // TODO move this to ConnectionToClient so the flag only lives on server + // connections? clients could use NetworkClient.ready to avoid redundant + // state. + public bool isReady; + + /// Last time a message was received for this connection. Includes system and user messages. + public float lastMessageTime; + + /// This connection's main object (usually the player object). + public NetworkIdentity identity { get; internal set; } + + /// All NetworkIdentities owned by this connection. Can be main player, pets, etc. + // .owned is now valid both on server and on client. + // IMPORTANT: this needs to be , not . + // fixes a bug where DestroyOwnedObjects wouldn't find the + // netId anymore: https://github.com/vis2k/Mirror/issues/1380 + // Works fine with NetworkIdentity pointers though. + public readonly HashSet owned = new HashSet(); + + // batching from server to client & client to server. + // fewer transport calls give us significantly better performance/scale. + // + // for a 64KB max message transport and 64 bytes/message on average, we + // reduce transport calls by a factor of 1000. + // + // depending on the transport, this can give 10x performance. + // + // Dictionary because we have multiple channels. + protected Dictionary batches = new Dictionary(); + + /// last batch's remote timestamp. not interpolated. useful for NetworkTransform etc. + // for any given NetworkMessage/Rpc/Cmd/OnSerialize, this was the time + // on the REMOTE END when it was sent. + // + // NOTE: this is NOT in NetworkTime, it needs to be per-connection + // because the server receives different batch timestamps from + // different connections. + public double remoteTimeStamp { get; internal set; } + + internal NetworkConnection() + { + // set lastTime to current time when creating connection to make + // sure it isn't instantly kicked for inactivity + lastMessageTime = Time.time; + } + + // TODO if we only have Reliable/Unreliable, then we could initialize + // two batches and avoid this code + protected Batcher GetBatchForChannelId(int channelId) + { + // get existing or create new writer for the channelId + Batcher batch; + if (!batches.TryGetValue(channelId, out batch)) + { + // get max batch size for this channel + int threshold = Transport.active.GetBatchThreshold(channelId); + + // create batcher + batch = new Batcher(threshold); + batches[channelId] = batch; + } + return batch; + } + + // Send stage one: NetworkMessage + /// Send a NetworkMessage to this connection over the given channel. + public void Send(T message, int channelId = Channels.Reliable) + where T : struct, NetworkMessage + { + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // pack message + NetworkMessages.Pack(message, writer); + + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkConnection.Send: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + + // send allocation free + NetworkDiagnostics.OnSend(message, channelId, writer.Position, 1); + Send(writer.ToArraySegment(), channelId); + } + } + + // Send stage two: serialized NetworkMessage as ArraySegment + // internal because no one except Mirror should send bytes directly to + // the client. they would be detected as a message. send messages instead. + // => make sure to validate message size before calling Send! + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal virtual void Send(ArraySegment segment, int channelId = Channels.Reliable) + { + //Debug.Log($"ConnectionSend {this} bytes:{BitConverter.ToString(segment.Array, segment.Offset, segment.Count)}"); + + // add to batch no matter what. + // batching will try to fit as many as possible into MTU. + // but we still allow > MTU, e.g. kcp max packet size 144kb. + // those are simply sent as single batches. + // + // IMPORTANT: do NOT send > batch sized messages directly: + // - data race: large messages would be sent directly. small + // messages would be sent in the batch at the end of frame + // - timestamps: if batching assumes a timestamp, then large + // messages need that too. + // + // NOTE: we ALWAYS batch. it's not optional, because the + // receiver needs timestamps for NT etc. + // + // NOTE: we do NOT ValidatePacketSize here yet. the final packet + // will be the full batch, including timestamp. + GetBatchForChannelId(channelId).AddMessage(segment, NetworkTime.localTime); + } + + // Send stage three: hand off to transport + protected abstract void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable); + + // flush batched messages at the end of every Update. + internal virtual void Update() + { + // go through batches for all channels + // foreach ((int key, Batcher batcher) in batches) // Unity 2020 doesn't support deconstruct yet + foreach (KeyValuePair kvp in batches) + { + // make and send as many batches as necessary from the stored + // messages. + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // make a batch with our local time (double precision) + while (kvp.Value.GetBatch(writer)) + { + // message size is validated in Send, with test coverage. + // we can send directly without checking again. + ArraySegment segment = writer.ToArraySegment(); + + // send to transport + SendToTransport(segment, kvp.Key); + //UnityEngine.Debug.Log($"sending batch of {writer.Position} bytes for channel={kvp.Key} connId={connectionId}"); + + // reset writer for each new batch + writer.Position = 0; + } + } + } + } + + /// Check if we received a message within the last 'timeout' seconds. + internal virtual bool IsAlive(float timeout) => Time.time - lastMessageTime < timeout; + + /// Disconnects this connection. + // for future reference, here is how Disconnects work in Mirror. + // + // first, there are two types of disconnects: + // * voluntary: the other end simply disconnected + // * involuntary: server disconnects a client by itself + // + // UNET had special (complex) code to handle both cases differently. + // + // Mirror handles both cases the same way: + // * Disconnect is called from TOP to BOTTOM + // NetworkServer/Client -> NetworkConnection -> Transport.Disconnect() + // * Disconnect is handled from BOTTOM to TOP + // Transport.OnDisconnected -> ... + // + // in other words, calling Disconnect() does no cleanup whatsoever. + // it simply asks the transport to disconnect. + // then later the transport events will do the clean up. + public abstract void Disconnect(); + + // cleanup is called before the connection is removed. + // return any batches' pooled writers before the connection disappears. + // otherwise if a connection disappears before flushing, writers would + // never be returned to the pool. + public virtual void Cleanup() + { + foreach (Batcher batcher in batches.Values) + { + batcher.Clear(); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkConnection.cs.meta b/Assets/Mirror/Core/NetworkConnection.cs.meta new file mode 100644 index 0000000..9516827 --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnection.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 11ea41db366624109af1f0834bcdde2f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkConnection.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkConnectionToClient.cs b/Assets/Mirror/Core/NetworkConnectionToClient.cs new file mode 100644 index 0000000..d80749c --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnectionToClient.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public class NetworkConnectionToClient : NetworkConnection + { + // rpcs are collected in a buffer, and then flushed out together. + // this way we don't need one NetworkMessage per rpc. + // => prepares for LocalWorldState as well. + // ensure max size when adding! + readonly NetworkWriter reliableRpcs = new NetworkWriter(); + readonly NetworkWriter unreliableRpcs = new NetworkWriter(); + + public virtual string address { get; private set; } + + /// Unique identifier for this connection that is assigned by the transport layer. + // assigned by transport, this id is unique for every connection on server. + // clients don't know their own id and they don't know other client's ids. + public readonly int connectionId; + + /// NetworkIdentities that this connection can see + // TODO move to server's NetworkConnectionToClient? + public readonly HashSet observing = new HashSet(); + + // unbatcher + public Unbatcher unbatcher = new Unbatcher(); + + // server runs a time snapshot interpolation for each client's local time. + // this is necessary for client auth movement to still be smooth on the + // server for host mode. + // TODO move them along server's timeline in the future. + // perhaps with an offset. + // for now, keep compatibility by manually constructing a timeline. + ExponentialMovingAverage driftEma; + ExponentialMovingAverage deliveryTimeEma; // average delivery time (standard deviation gives average jitter) + public double remoteTimeline; + public double remoteTimescale; + double bufferTimeMultiplier = 2; + double bufferTime => NetworkServer.sendInterval * bufferTimeMultiplier; + + // + readonly SortedList snapshots = new SortedList(); + + // Snapshot Buffer size limit to avoid ever growing list memory consumption attacks from clients. + public int snapshotBufferSizeLimit = 64; + + // ping for rtt (round trip time) + // useful for statistics, lag compensation, etc. + double lastPingTime = 0; + internal ExponentialMovingAverage _rtt = new ExponentialMovingAverage(NetworkTime.PingWindowSize); + + /// Round trip time (in seconds) that it takes a message to go server->client->server. + public double rtt => _rtt.Value; + + internal NetworkConnectionToClient() : base() { } + + public NetworkConnectionToClient(int networkConnectionId, string clientAddress = "localhost") : base() + { + connectionId = networkConnectionId; + address = clientAddress; + + // initialize EMA with 'emaDuration' seconds worth of history. + // 1 second holds 'sendRate' worth of values. + // multiplied by emaDuration gives n-seconds. + driftEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.snapshotSettings.driftEmaDuration); + deliveryTimeEma = new ExponentialMovingAverage(NetworkServer.sendRate * NetworkClient.snapshotSettings.deliveryTimeEmaDuration); + + // buffer limit should be at least multiplier to have enough in there + snapshotBufferSizeLimit = Mathf.Max((int)NetworkClient.snapshotSettings.bufferTimeMultiplier, snapshotBufferSizeLimit); + } + + public override string ToString() => $"connection({connectionId})"; + + public void OnTimeSnapshot(TimeSnapshot snapshot) + { + // protect against ever growing buffer size attacks + if (snapshots.Count >= snapshotBufferSizeLimit) return; + + // (optional) dynamic adjustment + if (NetworkClient.snapshotSettings.dynamicAdjustment) + { + // set bufferTime on the fly. + // shows in inspector for easier debugging :) + bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment( + NetworkServer.sendInterval, + deliveryTimeEma.StandardDeviation, + NetworkClient.snapshotSettings.dynamicAdjustmentTolerance + ); + // Debug.Log($"[Server]: {name} delivery std={serverDeliveryTimeEma.StandardDeviation} bufferTimeMult := {bufferTimeMultiplier} "); + } + + // insert into the server buffer & initialize / adjust / catchup + SnapshotInterpolation.InsertAndAdjust( + snapshots, + NetworkClient.snapshotSettings.bufferLimit, + snapshot, + ref remoteTimeline, + ref remoteTimescale, + NetworkServer.sendInterval, + bufferTime, + NetworkClient.snapshotSettings.catchupSpeed, + NetworkClient.snapshotSettings.slowdownSpeed, + ref driftEma, + NetworkClient.snapshotSettings.catchupNegativeThreshold, + NetworkClient.snapshotSettings.catchupPositiveThreshold, + ref deliveryTimeEma + ); + } + + public void UpdateTimeInterpolation() + { + // timeline starts when the first snapshot arrives. + if (snapshots.Count > 0) + { + // progress local timeline. + SnapshotInterpolation.StepTime(Time.unscaledDeltaTime, ref remoteTimeline, remoteTimescale); + + // progress local interpolation. + // TimeSnapshot doesn't interpolate anything. + // this is merely to keep removing older snapshots. + SnapshotInterpolation.StepInterpolation(snapshots, remoteTimeline, out _, out _, out _); + // Debug.Log($"NetworkClient SnapshotInterpolation @ {localTimeline:F2} t={t:F2}"); + } + } + + // Send stage three: hand off to transport + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable) => + Transport.active.ServerSend(connectionId, segment, channelId); + + protected virtual void UpdatePing() + { + // localTime (double) instead of Time.time for accuracy over days + if (NetworkTime.localTime >= lastPingTime + NetworkTime.PingInterval) + { + // TODO it would be safer for the server to store the last N + // messages' timestamp and only send a message number. + // This way client's can't just modify the timestamp. + // predictedTime parameter is 0 because the server doesn't predict. + NetworkPingMessage pingMessage = new NetworkPingMessage(NetworkTime.localTime, 0); + Send(pingMessage, Channels.Unreliable); + lastPingTime = NetworkTime.localTime; + } + } + + internal override void Update() + { + UpdatePing(); + base.Update(); + } + + /// Disconnects this connection. + public override void Disconnect() + { + // set not ready and handle clientscene disconnect in any case + // (might be client or host mode here) + isReady = false; + reliableRpcs.Position = 0; + unreliableRpcs.Position = 0; + Transport.active.ServerDisconnect(connectionId); + + // IMPORTANT: NetworkConnection.Disconnect() is NOT called for + // voluntary disconnects from the other end. + // -> so all 'on disconnect' cleanup code needs to be in + // OnTransportDisconnect, where it's called for both voluntary + // and involuntary disconnects! + } + + internal void AddToObserving(NetworkIdentity netIdentity) + { + observing.Add(netIdentity); + + // spawn identity for this conn + NetworkServer.ShowForConnection(netIdentity, this); + } + + internal void RemoveFromObserving(NetworkIdentity netIdentity, bool isDestroyed) + { + observing.Remove(netIdentity); + + if (!isDestroyed) + { + // hide identity for this conn + NetworkServer.HideForConnection(netIdentity, this); + } + } + + internal void RemoveFromObservingsObservers() + { + foreach (NetworkIdentity netIdentity in observing) + { + netIdentity.RemoveObserver(this); + } + observing.Clear(); + } + + internal void AddOwnedObject(NetworkIdentity obj) + { + owned.Add(obj); + } + + internal void RemoveOwnedObject(NetworkIdentity obj) + { + owned.Remove(obj); + } + + internal void DestroyOwnedObjects() + { + // create a copy because the list might be modified when destroying + HashSet tmp = new HashSet(owned); + foreach (NetworkIdentity netIdentity in tmp) + { + if (netIdentity != null) + { + // disown scene objects, destroy instantiated objects. + if (netIdentity.sceneId != 0) + NetworkServer.RemovePlayerForConnection(this, RemovePlayerOptions.KeepActive); + else + NetworkServer.Destroy(netIdentity.gameObject); + } + } + + // clear the hashset because we destroyed them all + owned.Clear(); + } + } +} diff --git a/Assets/Mirror/Core/NetworkConnectionToClient.cs.meta b/Assets/Mirror/Core/NetworkConnectionToClient.cs.meta new file mode 100644 index 0000000..d00cd5f --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnectionToClient.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: bb2195f8b29d24f0680a57fde2e9fd09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkConnectionToClient.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkConnectionToServer.cs b/Assets/Mirror/Core/NetworkConnectionToServer.cs new file mode 100644 index 0000000..496813d --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnectionToServer.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public class NetworkConnectionToServer : NetworkConnection + { + // Send stage three: hand off to transport + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void SendToTransport(ArraySegment segment, int channelId = Channels.Reliable) => + Transport.active.ClientSend(segment, channelId); + + /// Disconnects this connection. + public override void Disconnect() + { + // set not ready and handle clientscene disconnect in any case + // (might be client or host mode here) + // TODO remove redundant state. have one source of truth for .ready! + isReady = false; + NetworkClient.ready = false; + Transport.active.ClientDisconnect(); + } + } +} diff --git a/Assets/Mirror/Core/NetworkConnectionToServer.cs.meta b/Assets/Mirror/Core/NetworkConnectionToServer.cs.meta new file mode 100644 index 0000000..6f95398 --- /dev/null +++ b/Assets/Mirror/Core/NetworkConnectionToServer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 761977cbf38a34ded9dd89de45445675 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkConnectionToServer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkDiagnostics.cs b/Assets/Mirror/Core/NetworkDiagnostics.cs new file mode 100644 index 0000000..1cdc96f --- /dev/null +++ b/Assets/Mirror/Core/NetworkDiagnostics.cs @@ -0,0 +1,63 @@ +using System; + +namespace Mirror +{ + /// Profiling statistics for tool to subscribe to (profiler etc.) + public static class NetworkDiagnostics + { + /// Describes an outgoing message + public readonly struct MessageInfo + { + /// The message being sent + public readonly NetworkMessage message; + /// channel through which the message was sent + public readonly int channel; + /// how big was the message (does not include transport headers) + public readonly int bytes; + /// How many connections was the message sent to. + public readonly int count; + + internal MessageInfo(NetworkMessage message, int channel, int bytes, int count) + { + this.message = message; + this.channel = channel; + this.bytes = bytes; + this.count = count; + } + } + + /// Event for when Mirror sends a message. Can be subscribed to. + public static event Action OutMessageEvent; + + /// Event for when Mirror receives a message. Can be subscribed to. + public static event Action InMessageEvent; + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [UnityEngine.RuntimeInitializeOnLoadMethod] + static void ResetStatics() + { + InMessageEvent = null; + OutMessageEvent = null; + } + + internal static void OnSend(T message, int channel, int bytes, int count) + where T : struct, NetworkMessage + { + if (count > 0 && OutMessageEvent != null) + { + MessageInfo outMessage = new MessageInfo(message, channel, bytes, count); + OutMessageEvent?.Invoke(outMessage); + } + } + + internal static void OnReceive(T message, int channel, int bytes) + where T : struct, NetworkMessage + { + if (InMessageEvent != null) + { + MessageInfo inMessage = new MessageInfo(message, channel, bytes, 1); + InMessageEvent?.Invoke(inMessage); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkDiagnostics.cs.meta b/Assets/Mirror/Core/NetworkDiagnostics.cs.meta new file mode 100644 index 0000000..efefe99 --- /dev/null +++ b/Assets/Mirror/Core/NetworkDiagnostics.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c3754b39e5f8740fd93f3337b2c4274e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkDiagnostics.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkIdentity.cs b/Assets/Mirror/Core/NetworkIdentity.cs new file mode 100644 index 0000000..af60ef3 --- /dev/null +++ b/Assets/Mirror/Core/NetworkIdentity.cs @@ -0,0 +1,1411 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Mirror.RemoteCalls; +using UnityEngine; +using UnityEngine.Serialization; + +#if UNITY_EDITOR +using UnityEditor; + +#if UNITY_2021_2_OR_NEWER +using UnityEditor.SceneManagement; +#else +using UnityEditor.Experimental.SceneManagement; +#endif +#endif + +namespace Mirror +{ + // Default = use interest management + // ForceHidden = useful to hide monsters while they respawn etc. + // ForceShown = useful to have score NetworkIdentities that always broadcast + // to everyone etc. + public enum Visibility { Default, ForceHidden, ForceShown } + + public struct NetworkIdentitySerialization + { + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks + public int tick; + public NetworkWriter ownerWriter; + public NetworkWriter observersWriter; + + public void ResetWriters() + { + ownerWriter.Position = 0; + observersWriter.Position = 0; + } + } + + /// NetworkIdentity identifies objects across the network. + [DisallowMultipleComponent] + // NetworkIdentity.Awake initializes all NetworkComponents. + // let's make sure it's always called before their Awake's. + [DefaultExecutionOrder(-1)] + [AddComponentMenu("Network/Network Identity")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-identity")] + public sealed class NetworkIdentity : MonoBehaviour + { + /// Returns true if running as a client and this object was spawned by a server. + // + // IMPORTANT: + // OnStartClient sets it to true. we NEVER set it to false after. + // otherwise components like Skillbars couldn't use OnDestroy() + // for saving, etc. since isClient may have been reset before + // OnDestroy was called. + // + // we also DO NOT make it dependent on NetworkClient.active or similar. + // we set it, then never change it. that's the user's expectation too. + // + // => fixes https://github.com/vis2k/Mirror/issues/1475 + public bool isClient { get; internal set; } + + /// Returns true if NetworkServer.active and server is not stopped. + // + // IMPORTANT: + // OnStartServer sets it to true. we NEVER set it to false after. + // otherwise components like Skillbars couldn't use OnDestroy() + // for saving, etc. since isServer may have been reset before + // OnDestroy was called. + // + // we also DO NOT make it dependent on NetworkServer.active or similar. + // we set it, then never change it. that's the user's expectation too. + // + // => fixes https://github.com/vis2k/Mirror/issues/1484 + // => fixes https://github.com/vis2k/Mirror/issues/2533 + public bool isServer { get; internal set; } + + /// Return true if this object represents the player on the local machine. + // + // IMPORTANT: + // OnStartLocalPlayer sets it to true. we NEVER set it to false after. + // otherwise components like Skillbars couldn't use OnDestroy() + // for saving, etc. since isLocalPlayer may have been reset before + // OnDestroy was called. + // + // we also DO NOT make it dependent on NetworkClient.localPlayer or similar. + // we set it, then never change it. that's the user's expectation too. + // + // => fixes https://github.com/vis2k/Mirror/issues/2615 + public bool isLocalPlayer { get; internal set; } + + /// True if this object only exists on the server + public bool isServerOnly => isServer && !isClient; + + /// True if this object exists on a client that is not also acting as a server. + public bool isClientOnly => isClient && !isServer; + + /// isOwned is true on the client if this NetworkIdentity is one of the .owned entities of our connection on the server. + // for example: main player & pets are owned. monsters & npcs aren't. + public bool isOwned { get; internal set; } + + // internal so NetworkManager can reset it from StopClient. + internal bool clientStarted; + + /// The set of network connections (players) that can see this object. + public readonly Dictionary observers = + new Dictionary(); + + /// The unique network Id of this object (unique at runtime). + public uint netId { get; internal set; } + + /// Unique identifier for NetworkIdentity objects within a scene, used for spawning scene objects. + // persistent scene id (see AssignSceneID comments) + [FormerlySerializedAs("m_SceneId"), HideInInspector] + public ulong sceneId; + + // assetId used to spawn prefabs across the network. + // originally a Guid, but a 4 byte uint is sufficient + // (as suggested by james) + // + // it's also easier to work with for serialization etc. + // serialized and visible in inspector for easier debugging + [SerializeField, HideInInspector] uint _assetId; + + // The AssetId trick: + // Ideally we would have a serialized 'Guid m_AssetId' but Unity can't + // serialize it because Guid's internal bytes are private + // + // Using just the Guid string would work, but it's 32 chars long and + // would then be sent over the network as 64 instead of 16 bytes + // + // => The solution is to serialize the string internally here and then + // use the real 'Guid' type for everything else via .assetId + public uint assetId + { + get + { +#if UNITY_EDITOR + // old UNET comment: + // This is important because sometimes OnValidate does not run + // (like when adding NetworkIdentity to prefab with no child links) + if (_assetId == 0) + SetupIDs(); +#endif + return _assetId; + } + // assetId is set internally when creating or duplicating a prefab + internal set + { + // should never be empty + if (value == 0) + { + Debug.LogError($"Can not set AssetId to empty guid on NetworkIdentity '{name}', old assetId '{_assetId}'"); + return; + } + + // always set it otherwise. + // for new prefabs, it will set from 0 to N. + // for duplicated prefabs, it will set from N to M. + // either way, it's always set to a valid GUID. + _assetId = value; + // Debug.Log($"Setting AssetId on NetworkIdentity '{name}', new assetId '{value:X4}'"); + } + } + + /// Make this object only exist when the game is running as a server (or host). + [FormerlySerializedAs("m_ServerOnly")] + [Tooltip("Prevents this object from being spawned / enabled on clients")] + public bool serverOnly; + + // Set before Destroy is called so that OnDestroy doesn't try to destroy + // the object again + internal bool destroyCalled; + + /// Client's network connection to the server. This is only valid for player objects on the client. + // TODO change to NetworkConnectionToServer, but might cause some breaking + public NetworkConnection connectionToServer { get; internal set; } + + /// Server's network connection to the client. This is only valid for client-owned objects (including the Player object) on the server. + public NetworkConnectionToClient connectionToClient + { + get => _connectionToClient; + internal set + { + _connectionToClient?.RemoveOwnedObject(this); + _connectionToClient = value; + _connectionToClient?.AddOwnedObject(this); + } + } + NetworkConnectionToClient _connectionToClient; + + // get all NetworkBehaviour components + public NetworkBehaviour[] NetworkBehaviours { get; private set; } + + // to save bandwidth, we send one 64 bit dirty mask + // instead of 1 byte index per dirty component. + // which means we can't allow > 64 components (it's enough). + const int MaxNetworkBehaviours = 64; + + // current visibility + // + // Default = use interest management + // ForceHidden = useful to hide monsters while they respawn etc. + // ForceShown = useful to have score NetworkIdentities that always broadcast + // to everyone etc. + [Tooltip("Visibility can overwrite interest management. ForceHidden can be useful to hide monsters while they respawn. ForceShown can be useful for score NetworkIdentities that should always broadcast to everyone in the world.")] + [FormerlySerializedAs("visible")] + public Visibility visibility = Visibility.Default; + + // broadcasting serializes all entities around a player for each player. + // we don't want to serialize one entity twice in the same tick. + // so we cache the last serialization and remember the timestamp so we + // know which Update it was serialized. + // (timestamp is the same while inside Update) + // => this way we don't need to pool thousands of writers either. + // => way easier to store them per object + NetworkIdentitySerialization lastSerialization = new NetworkIdentitySerialization + { + ownerWriter = new NetworkWriter(), + observersWriter = new NetworkWriter() + }; + + // Keep track of all sceneIds to detect scene duplicates + static readonly Dictionary sceneIds = + new Dictionary(); + + // Helper function to handle Command/Rpc + internal void HandleRemoteCall(byte componentIndex, ushort functionHash, RemoteCallType remoteCallType, NetworkReader reader, NetworkConnectionToClient senderConnection = null) + { + // check if unity object has been destroyed + if (this == null) + { + Debug.LogWarning($"{remoteCallType} [{functionHash}] received for deleted object [netId={netId}]"); + return; + } + + // find the right component to invoke the function on + if (componentIndex >= NetworkBehaviours.Length) + { + Debug.LogWarning($"Component [{componentIndex}] not found for [netId={netId}]"); + return; + } + + NetworkBehaviour invokeComponent = NetworkBehaviours[componentIndex]; + if (!RemoteProcedureCalls.Invoke(functionHash, remoteCallType, reader, invokeComponent, senderConnection)) + { + Debug.LogError($"Found no receiver for incoming {remoteCallType} [{functionHash}] on {gameObject.name}, the server and client should have the same NetworkBehaviour instances [netId={netId}]."); + } + } + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + // internal so it can be called from NetworkServer & NetworkClient + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + internal static void ResetStatics() + { + // reset ALL statics + ResetClientStatics(); + ResetServerStatics(); + } + + // reset only client sided statics. + // don't touch server statics when calling StopClient in host mode. + // https://github.com/vis2k/Mirror/issues/2954 + internal static void ResetClientStatics() + { + previousLocalPlayer = null; + clientAuthorityCallback = null; + } + + internal static void ResetServerStatics() + { + nextNetworkId = 1; + } + + /// Gets the NetworkIdentity from the sceneIds dictionary with the corresponding id + public static NetworkIdentity GetSceneIdentity(ulong id) => sceneIds[id]; + + static uint nextNetworkId = 1; + internal static uint GetNextNetworkId() => nextNetworkId++; + + /// Resets nextNetworkId = 1 + public static void ResetNextNetworkId() => nextNetworkId = 1; + + /// The delegate type for the clientAuthorityCallback. + public delegate void ClientAuthorityCallback(NetworkConnectionToClient conn, NetworkIdentity identity, bool authorityState); + + /// A callback that can be populated to be notified when the client-authority state of objects changes. + public static event ClientAuthorityCallback clientAuthorityCallback; + + // hasSpawned should always be false before runtime + [SerializeField, HideInInspector] bool hasSpawned; + public bool SpawnedFromInstantiate { get; private set; } + + // NetworkBehaviour components are initialized in Awake once. + // Changing them at runtime would get client & server out of sync. + // BUT internal so tests can add them after creating the NetworkIdentity + internal void InitializeNetworkBehaviours() + { + // Get all NetworkBehaviour components, including children. + // Some users need NetworkTransform on child bones, etc. + // => Deterministic: https://forum.unity.com/threads/getcomponentsinchildren.4582/#post-33983 + // => Never null. GetComponents returns [] if none found. + // => Include inactive. We need all child components. + NetworkBehaviours = GetComponentsInChildren(true); + ValidateComponents(); + + // initialize each one + for (int i = 0; i < NetworkBehaviours.Length; ++i) + { + NetworkBehaviour component = NetworkBehaviours[i]; + component.netIdentity = this; + component.ComponentIndex = (byte)i; + } + } + + void ValidateComponents() + { + if (NetworkBehaviours == null) + { + Debug.LogError($"NetworkBehaviours array is null on {gameObject.name}!\n" + + $"Typically this can happen when a networked object is a child of a " + + $"non-networked parent that's disabled, preventing Awake on the networked object " + + $"from being invoked, where the NetworkBehaviours array is initialized.", gameObject); + } + else if (NetworkBehaviours.Length > MaxNetworkBehaviours) + { + Debug.LogError($"NetworkIdentity {name} has too many NetworkBehaviour components: only {MaxNetworkBehaviours} NetworkBehaviour components are allowed in order to save bandwidth.", this); + } + } + + // Awake is only called in Play mode. + // internal so we can call it during unit tests too. + internal void Awake() + { + // initialize NetworkBehaviour components. + // Awake() is called immediately after initialization. + // no one can overwrite it because NetworkIdentity is sealed. + // => doing it here is the fastest and easiest solution. + InitializeNetworkBehaviours(); + + if (hasSpawned) + { + Debug.LogError($"{name} has already spawned. Don't call Instantiate for NetworkIdentities that were in the scene since the beginning (aka scene objects). Otherwise the client won't know which object to use for a SpawnSceneObject message."); + SpawnedFromInstantiate = true; + Destroy(gameObject); + } + hasSpawned = true; + } + + void OnValidate() + { + // OnValidate is not called when using Instantiate, so we can use + // it to make sure that hasSpawned is false + hasSpawned = false; + +#if UNITY_EDITOR + DisallowChildNetworkIdentities(); + SetupIDs(); +#endif + } + + // expose our AssetId Guid to uint mapping code in case projects need to map Guids to uint as well. + // this way their projects won't break if we change our mapping algorithm. + // needs to be available at runtime / builds, don't wrap in #if UNITY_EDITOR + public static uint AssetGuidToUint(Guid guid) => (uint)guid.GetHashCode(); // deterministic + +#if UNITY_EDITOR + // child NetworkIdentities are not supported. + // Disallow them and show an error for the user to fix. + // This needs to work for Prefabs & Scene objects, so the previous check + // in NetworkClient.RegisterPrefab is not enough. + void DisallowChildNetworkIdentities() + { +#if UNITY_2020_3_OR_NEWER + NetworkIdentity[] identities = GetComponentsInChildren(true); +#else + NetworkIdentity[] identities = GetComponentsInChildren(); +#endif + if (identities.Length > 1) + { + // always log the next child component so it's easy to fix. + // if there are multiple, then after removing it'll log the next. + Debug.LogError($"'{name}' has another NetworkIdentity component on '{identities[1].name}'. There should only be one NetworkIdentity, and it must be on the root object. Please remove the other one.", this); + } + } + + void AssignAssetID(string path) + { + // only set if not empty. fixes https://github.com/vis2k/Mirror/issues/2765 + if (!string.IsNullOrWhiteSpace(path)) + { + // if we generate the assetId then we MUST be sure to set dirty + // in order to save the prefab object properly. otherwise it + // would be regenerated every time we reopen the prefab. + // -> Undo.RecordObject is the new EditorUtility.SetDirty! + // -> we need to call it before changing. + // + // to verify this, duplicate a prefab and double click to open it. + // add a log message if "_assetId != before_". + // without RecordObject, it'll log every time because it's not saved. + Undo.RecordObject(this, "Assigned AssetId"); + + // uint before = _assetId; + Guid guid = new Guid(AssetDatabase.AssetPathToGUID(path)); + assetId = AssetGuidToUint(guid); + // if (_assetId != before) Debug.Log($"Assigned assetId={assetId} to {name}"); + } + } + + void AssignAssetID(GameObject prefab) => AssignAssetID(AssetDatabase.GetAssetPath(prefab)); + + // persistent sceneId assignment + // (because scene objects have no persistent unique ID in Unity) + // + // original UNET used OnPostProcessScene to assign an index based on + // FindObjectOfType order. + // -> this didn't work because FindObjectOfType order isn't deterministic. + // -> one workaround is to sort them by sibling paths, but it can still + // get out of sync when we open scene2 in editor and we have + // DontDestroyOnLoad objects that messed with the sibling index. + // + // we absolutely need a persistent id. challenges: + // * it needs to be 0 for prefabs + // => we set it to 0 in SetupIDs() if prefab! + // * it needs to be only assigned in edit time, not at runtime because + // only the objects that were in the scene since beginning should have + // a scene id. + // => Application.isPlaying check solves that + // * it needs to detect duplicated sceneIds after duplicating scene + // objects + // => sceneIds dict takes care of that + // * duplicating the whole scene file shouldn't result in duplicate + // scene objects + // => buildIndex is shifted into sceneId for that. + // => if we have no scenes in build index then it doesn't matter + // because by definition a build can't switch to other scenes + // => if we do have scenes in build index then it will be != -1 + // note: the duplicated scene still needs to be opened once for it to + // be set properly + // * scene objects need the correct scene index byte even if the scene's + // build index was changed or a duplicated scene wasn't opened yet. + // => OnPostProcessScene is the only function that gets called for + // each scene before runtime, so this is where we set the scene + // byte. + // * disabled scenes in build settings should result in same scene index + // in editor and in build + // => .gameObject.scene.buildIndex filters out disabled scenes by + // default + // * generated sceneIds absolutely need to set scene dirty and force the + // user to resave. + // => Undo.RecordObject does that perfectly. + // * sceneIds should never be generated temporarily for unopened scenes + // when building, otherwise editor and build get out of sync + // => BuildPipeline.isBuildingPlayer check solves that + void AssignSceneID() + { + // we only ever assign sceneIds at edit time, never at runtime. + // by definition, only the original scene objects should get one. + // -> if we assign at runtime then server and client would generate + // different random numbers! + if (Application.isPlaying) + return; + + // no valid sceneId yet, or duplicate? + bool duplicate = sceneIds.TryGetValue(sceneId, out NetworkIdentity existing) && existing != null && existing != this; + if (sceneId == 0 || duplicate) + { + // clear in any case, because it might have been a duplicate + sceneId = 0; + + // if a scene was never opened and we are building it, then a + // sceneId would be assigned to build but not saved in editor, + // resulting in them getting out of sync. + // => don't ever assign temporary ids. they always need to be + // permanent + // => throw an exception to cancel the build and let the user + // know how to fix it! + if (BuildPipeline.isBuildingPlayer) + throw new InvalidOperationException($"Scene {gameObject.scene.path} needs to be opened and resaved before building, because the scene object {name} has no valid sceneId yet."); + + // if we generate the sceneId then we MUST be sure to set dirty + // in order to save the scene object properly. otherwise it + // would be regenerated every time we reopen the scene, and + // upgrading would be very difficult. + // -> Undo.RecordObject is the new EditorUtility.SetDirty! + // -> we need to call it before changing. + Undo.RecordObject(this, "Generated SceneId"); + + // generate random sceneId part (0x00000000FFFFFFFF) + uint randomId = Utils.GetTrueRandomUInt(); + + // only assign if not a duplicate of an existing scene id + // (small chance, but possible) + duplicate = sceneIds.TryGetValue(randomId, out existing) && existing != null && existing != this; + if (!duplicate) + { + sceneId = randomId; + //Debug.Log($"{name} in scene {gameObject.scene.name} sceneId assigned to:{sceneId:X}"); + } + } + + // add to sceneIds dict no matter what + // -> even if we didn't generate anything new, because we still need + // existing sceneIds in there to check duplicates + sceneIds[sceneId] = this; + } + + // copy scene path hash into sceneId for scene objects. + // this is the only way for scene file duplication to not contain + // duplicate sceneIds as it seems. + // -> sceneId before: 0x00000000AABBCCDD + // -> then we clear the left 4 bytes, so that our 'OR' uses 0x00000000 + // -> then we OR the hash into the 0x00000000 part + // -> buildIndex is not enough, because Editor and Build have different + // build indices if there are disabled scenes in build settings, and + // if no scene is in build settings then Editor and Build have + // different indices too (Editor=0, Build=-1) + // => ONLY USE THIS FROM POSTPROCESSSCENE! + public void SetSceneIdSceneHashPartInternal() + { + // Use `ToLower` to that because BuildPipeline.BuildPlayer is case insensitive but hash is case sensitive + // If the scene in the project is `forest.unity` but `Forest.unity` is given to BuildPipeline then the + // BuildPipeline will use `Forest.unity` for the build and create a different hash than the editor will. + // Using ToLower will mean the hash will be the same for these 2 paths + // Assets/Scenes/Forest.unity + // Assets/Scenes/forest.unity + string scenePath = gameObject.scene.path.ToLower(); + + // get deterministic scene hash + uint pathHash = (uint)scenePath.GetStableHashCode(); + + // shift hash from 0x000000FFFFFFFF to 0xFFFFFFFF00000000 + ulong shiftedHash = (ulong)pathHash << 32; + + // OR into scene id + sceneId = (sceneId & 0xFFFFFFFF) | shiftedHash; + + // log it. this is incredibly useful to debug sceneId issues. + //Debug.Log($"{name} in scene {gameObject.scene.name} scene index hash {pathHash:X} copied into sceneId {sceneId:X}"); + } + + void SetupIDs() + { + // is this a prefab? + if (Utils.IsPrefab(gameObject)) + { + // force 0 for prefabs + sceneId = 0; + AssignAssetID(gameObject); + } + // are we currently in prefab editing mode? aka prefab stage + // => check prefabstage BEFORE SceneObjectWithPrefabParent + // (fixes https://github.com/vis2k/Mirror/issues/976) + // => if we don't check GetCurrentPrefabStage and only check + // GetPrefabStage(gameObject), then the 'else' case where we + // assign a sceneId and clear the assetId would still be + // triggered for prefabs. in other words: if we are in prefab + // stage, do not bother with anything else ever! + else if (PrefabStageUtility.GetCurrentPrefabStage() != null) + { + // when modifying a prefab in prefab stage, Unity calls + // OnValidate for that prefab and for all scene objects based on + // that prefab. + // + // is this GameObject the prefab that we modify, and not just a + // scene object based on the prefab? + // * GetCurrentPrefabStage = 'are we editing ANY prefab?' + // * GetPrefabStage(go) = 'are we editing THIS prefab?' + if (PrefabStageUtility.GetPrefabStage(gameObject) != null) + { + // force 0 for prefabs + sceneId = 0; + //Debug.Log($"{name} scene:{gameObject.scene.name} sceneid reset to 0 because CurrentPrefabStage={PrefabStageUtility.GetCurrentPrefabStage()} PrefabStage={PrefabStageUtility.GetPrefabStage(gameObject)}"); + + // get path from PrefabStage for this prefab +#if UNITY_2020_1_OR_NEWER + string path = PrefabStageUtility.GetPrefabStage(gameObject).assetPath; +#else + string path = PrefabStageUtility.GetPrefabStage(gameObject).prefabAssetPath; +#endif + + AssignAssetID(path); + } + } + // is this a scene object with prefab parent? + else if (Utils.IsSceneObjectWithPrefabParent(gameObject, out GameObject prefab)) + { + AssignSceneID(); + AssignAssetID(prefab); + } + else + { + AssignSceneID(); + + // IMPORTANT: DO NOT clear assetId at runtime! + // => fixes a bug where clicking any of the NetworkIdentity + // properties (like ServerOnly/ForceHidden) at runtime would + // call OnValidate + // => OnValidate gets into this else case here because prefab + // connection isn't known at runtime + // => then we would clear the previously assigned assetId + // => and NetworkIdentity couldn't be spawned on other clients + // anymore because assetId was cleared + if (!EditorApplication.isPlaying) + { + _assetId = 0; + } + // don't log. would show a lot when pressing play in uMMORPG/uSurvival/etc. + //else Debug.Log($"Avoided clearing assetId at runtime for {name} after (probably) clicking any of the NetworkIdentity properties."); + } + } +#endif + + // OnDestroy is called for all SPAWNED NetworkIdentities + // => scene objects aren't destroyed. it's not called for them. + // + // Note: Unity will Destroy all networked objects on Scene Change, so we + // have to handle that here silently. That means we cannot have any + // warning or logging in this method. + void OnDestroy() + { + // Objects spawned from Instantiate are not allowed so are destroyed right away + // we don't want to call NetworkServer.Destroy if this is the case + if (SpawnedFromInstantiate) + return; + + // If false the object has already been unspawned + // if it is still true, then we need to unspawn it + // if destroy is already called don't call it again + if (isServer && !destroyCalled) + { + // Do not add logging to this (see above) + NetworkServer.Destroy(gameObject); + } + + if (isLocalPlayer) + { + // previously there was a bug where isLocalPlayer was + // false in OnDestroy because it was dynamically defined as: + // isLocalPlayer => NetworkClient.localPlayer == this + // we fixed it by setting isLocalPlayer manually and never + // resetting it. + // + // BUT now we need to be aware of a possible data race like in + // our rooms example: + // => GamePlayer is in world + // => player returns to room + // => GamePlayer is destroyed + // => NetworkClient.localPlayer is set to RoomPlayer + // => GamePlayer.OnDestroy is called 1 frame later + // => GamePlayer.OnDestroy 'isLocalPlayer' is true, so here we + // are trying to clear NetworkClient.localPlayer + // => which would overwrite the new RoomPlayer local player + // + // FIXED by simply only clearing if NetworkClient.localPlayer + // still points to US! + // => see also: https://github.com/vis2k/Mirror/issues/2635 + if (NetworkClient.localPlayer == this) + NetworkClient.localPlayer = null; + } + + if (isClient) + { + // ServerChangeScene doesn't send destroy messages. + // some identities may persist in DDOL. + // some are destroyed by scene change. + // if an identity is still in .owned remove it. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3308 + if (NetworkClient.connection != null) + NetworkClient.connection.owned.Remove(this); + + // if an identity is still in .spawned, remove it too. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3324 + // + // however, verify that spawned[netId] is this NetworkIdentity + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3785 + // - server: netId=42 walks out of and back into AOI range in same frame + // - client frame 1: + // on_destroymsg(42) -> NetworkClient.DestroyObject -> GameObject.Destroy(42) // next frame + // on_spawnmsg(42) -> NetworkClient.SpawnPrefab -> Instantiate(42) -> spawned[42]=new_identity + // - client frame 2: + // Unity destroys the old 42 + // NetworkIdentity.OnDestroy removes .spawned[42] which is new_identity not old_identity + // new_identity becomes orphaned + // + // solution: only remove if spawned[netId] is this NetworkIdentity or null + if (NetworkClient.spawned.TryGetValue(netId, out NetworkIdentity entry)) + { + if (entry == this || entry == null) + NetworkClient.spawned.Remove(netId); + } + } + + // workaround for cyclid NI<->NB reference causing memory leaks + // after Destroy. [Credits: BigBoxVR/R.S.] + // TODO report this to Unity! + this.NetworkBehaviours = null; + } + + internal void OnStartServer() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStartServer should be caught, so that one + // component's exception doesn't stop all other components from + // being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStartServer(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal void OnStopServer() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStartServer should be caught, so that one + // component's exception doesn't stop all other components from + // being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStopServer(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal void OnStartClient() + { + if (clientStarted) return; + + clientStarted = true; + + // Debug.Log($"OnStartClient {gameObject} netId:{netId}"); + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStartClient should be caught, so that one + // component's exception doesn't stop all other components from + // being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + // user implemented startup + comp.OnStartClient(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal void OnStopClient() + { + // In case this object was destroyed already don't call + // OnStopClient if OnStartClient hasn't been called. + if (!clientStarted) return; + + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStopClient should be caught, so that + // one component's exception doesn't stop all other components + // from being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStopClient(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal static NetworkIdentity previousLocalPlayer = null; + internal void OnStartLocalPlayer() + { + // ensure OnStartLocalPlayer is only called once. + // Room demo would call it multiple times: + // - once from ApplySpawnPayload + // - once from OnObjectSpawnFinished + // + // to reproduce: + // - open room demo, add the 3 scenes to build settings + // - add OnStartLocalPlayer log to RoomPlayer prefab + // - build, run server-only + // - in editor, connect, press ready + // - in server, start game + // - notice multiple OnStartLocalPlayer logs in editor client + // + // explanation: + // we send the spawn message multiple times. Whenever an object changes + // authority, we send the spawn message again for the object. This is + // necessary because we need to reinitialize all variables when + // ownership change due to sync to owner feature. + // Without this static, the second time we get the spawn message we + // would call OnStartLocalPlayer again on the same object + if (previousLocalPlayer == this) + return; + previousLocalPlayer = this; + + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStartLocalPlayer should be caught, so that + // one component's exception doesn't stop all other components + // from being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStartLocalPlayer(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal void OnStopLocalPlayer() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStopLocalPlayer should be caught, so that + // one component's exception doesn't stop all other components + // from being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStopLocalPlayer(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + // build dirty mask for server owner & observers (= all dirty components). + // faster to do it in one iteration instead of iterating separately. + (ulong, ulong) ServerDirtyMasks(bool initialState) + { + ulong ownerMask = 0; + ulong observerMask = 0; + + NetworkBehaviour[] components = NetworkBehaviours; + for (int i = 0; i < components.Length; ++i) + { + NetworkBehaviour component = components[i]; + ulong nthBit = 1ul << i; + + bool dirty = component.IsDirty(); + + // owner needs to be considered for both SyncModes, because + // Observers mode always includes the Owner. + // + // for initial, it should always sync owner. + // for delta, only for ServerToClient and only if dirty. + // ClientToServer comes from the owner client. + if (initialState || (component.syncDirection == SyncDirection.ServerToClient && dirty)) + ownerMask |= nthBit; + + // observers need to be considered only in Observers mode, + // otherwise they receive no sync data of this component ever. + if (component.syncMode == SyncMode.Observers) + { + // for initial, it should always sync to observers. + // for delta, only if dirty. + // SyncDirection is irrelevant, as both are broadcast to + // observers which aren't the owner. + if (initialState || dirty) + observerMask |= nthBit; + } + } + + return (ownerMask, observerMask); + } + + // build dirty mask for client. + // server always knows initialState, so we don't need it here. + ulong ClientDirtyMask() + { + ulong mask = 0; + + NetworkBehaviour[] components = NetworkBehaviours; + for (int i = 0; i < components.Length; ++i) + { + // on the client, we need to consider different sync scenarios: + // + // ServerToClient SyncDirection: + // do nothing. + // ClientToServer SyncDirection: + // serialize only if owned. + + // on client, only consider owned components with SyncDirection to server + NetworkBehaviour component = components[i]; + ulong nthBit = 1ul << i; + + if (isOwned && component.syncDirection == SyncDirection.ClientToServer) + { + // set the n-th bit if dirty + // shifting from small to large numbers is varint-efficient. + if (component.IsDirty()) mask |= nthBit; + } + } + + return mask; + } + + // check if n-th component is dirty. + // in other words, if it has the n-th bit set in the dirty mask. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsDirty(ulong mask, int index) + { + ulong nthBit = 1ul << index; + return (mask & nthBit) != 0; + } + + // serialize components into writer on the server. + // check ownerWritten/observersWritten to know if anything was written + internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, NetworkWriter observersWriter) + { + // ensure NetworkBehaviours are valid before usage + ValidateComponents(); + NetworkBehaviour[] components = NetworkBehaviours; + + // check which components are dirty for owner / observers. + // this is quite complicated with SyncMode + SyncDirection. + // see the function for explanation. + // + // instead of writing a 1 byte index per component, + // we limit components to 64 bits and write one ulong instead. + // the ulong is also varint compressed for minimum bandwidth. + (ulong ownerMask, ulong observerMask) = ServerDirtyMasks(initialState); + + // if nothing dirty, then don't even write the mask. + // otherwise, every unchanged object would send a 1 byte dirty mask! + if (ownerMask != 0) Compression.CompressVarUInt(ownerWriter, ownerMask); + if (observerMask != 0) Compression.CompressVarUInt(observersWriter, observerMask); + + // serialize all components + // perf: only iterate if either dirty mask has dirty bits. + if ((ownerMask | observerMask) != 0) + { + for (int i = 0; i < components.Length; ++i) + { + NetworkBehaviour comp = components[i]; + + // is the component dirty for anyone (owner or observers)? + // may be serialized to owner, observer, both, or neither. + // + // OnSerialize should only be called once. + // this is faster, and it cleaner because it may set + // internal state, counters, logs, etc. + // + // previously we always serialized to owner and then copied + // the serialization to observers. however, since + // SyncDirection it's not guaranteed to be in owner anymore. + // so we need to serialize to temporary writer first. + // and then copy as needed. + bool ownerDirty = IsDirty(ownerMask, i); + bool observersDirty = IsDirty(observerMask, i); + if (ownerDirty || observersDirty) + { + // serialize into helper writer + using (NetworkWriterPooled temp = NetworkWriterPool.Get()) + { + comp.Serialize(temp, initialState); + ArraySegment segment = temp.ToArraySegment(); + + // copy to owner / observers as needed + if (ownerDirty) ownerWriter.WriteBytes(segment.Array, segment.Offset, segment.Count); + if (observersDirty) observersWriter.WriteBytes(segment.Array, segment.Offset, segment.Count); + } + + // clear dirty bits for the components that we serialized. + // do not clear for _all_ components, only the ones that + // were dirty and had their syncInterval elapsed. + // + // we don't want to clear bits before the syncInterval + // was elapsed, as then they wouldn't be synced. + // + // only clear for delta, not for full (spawn messages). + // otherwise if a player joins, we serialize monster, + // and shouldn't clear dirty bits not yet synced to + // other players. + if (!initialState) comp.ClearAllDirtyBits(); + } + } + } + } + + // serialize components into writer on the client. + internal void SerializeClient(NetworkWriter writer) + { + // ensure NetworkBehaviours are valid before usage + ValidateComponents(); + NetworkBehaviour[] components = NetworkBehaviours; + + // check which components are dirty. + // this is quite complicated with SyncMode + SyncDirection. + // see the function for explanation. + // + // instead of writing a 1 byte index per component, + // we limit components to 64 bits and write one ulong instead. + // the ulong is also varint compressed for minimum bandwidth. + ulong dirtyMask = ClientDirtyMask(); + + // varint compresses the mask to 1 byte in most cases. + // instead of writing an 8 byte ulong. + // 7 components fit into 1 byte. (previously 7 bytes) + // 11 components fit into 2 bytes. (previously 11 bytes) + // 16 components fit into 3 bytes. (previously 16 bytes) + // TODO imer: server knows amount of comps, write N bytes instead + + // if nothing dirty, then don't even write the mask. + // otherwise, every unchanged object would send a 1 byte dirty mask! + if (dirtyMask != 0) Compression.CompressVarUInt(writer, dirtyMask); + + // serialize all components + // perf: only iterate if dirty mask has dirty bits. + if (dirtyMask != 0) + { + // serialize all components + for (int i = 0; i < components.Length; ++i) + { + NetworkBehaviour comp = components[i]; + + // is this component dirty? + // reuse the mask instead of calling comp.IsDirty() again here. + if (IsDirty(dirtyMask, i)) + // if (isOwned && component.syncDirection == SyncDirection.ClientToServer) + { + // serialize into writer. + // server always knows initialState, we never need to send it + comp.Serialize(writer, false); + + // clear dirty bits for the components that we serialized. + // do not clear for _all_ components, only the ones that + // were dirty and had their syncInterval elapsed. + // + // we don't want to clear bits before the syncInterval + // was elapsed, as then they wouldn't be synced. + comp.ClearAllDirtyBits(); + } + } + } + } + + // deserialize components from the client on the server. + // there's no 'initialState'. server always knows the initial state. + internal bool DeserializeServer(NetworkReader reader) + { + // ensure NetworkBehaviours are valid before usage + ValidateComponents(); + NetworkBehaviour[] components = NetworkBehaviours; + + // first we deserialize the varinted dirty mask + ulong mask = Compression.DecompressVarUInt(reader); + + // now deserialize every dirty component + for (int i = 0; i < components.Length; ++i) + { + // was this one dirty? + if (IsDirty(mask, i)) + { + NetworkBehaviour comp = components[i]; + + // safety check to ensure clients can only modify their own + // ClientToServer components, nothing else. + if (comp.syncDirection == SyncDirection.ClientToServer) + { + // deserialize this component + // server always knows the initial state (initial=false) + // disconnect if failed, to prevent exploits etc. + if (!comp.Deserialize(reader, false)) return false; + + // server received state from the owner client. + // set dirty so it's broadcast to other clients too. + // + // note that we set the _whole_ component as dirty. + // everything will be broadcast to others. + // SetSyncVarDirtyBits() would be nicer, but not all + // components use [SyncVar]s. + comp.SetDirty(); + } + } + } + + // successfully deserialized everything + return true; + } + + // deserialize components from server on the client. + internal void DeserializeClient(NetworkReader reader, bool initialState) + { + // ensure NetworkBehaviours are valid before usage + ValidateComponents(); + NetworkBehaviour[] components = NetworkBehaviours; + + // first we deserialize the varinted dirty mask + ulong mask = Compression.DecompressVarUInt(reader); + + // now deserialize every dirty component + for (int i = 0; i < components.Length; ++i) + { + // was this one dirty? + if (IsDirty(mask, i)) + { + // deserialize this component + NetworkBehaviour comp = components[i]; + comp.Deserialize(reader, initialState); + } + } + } + + // get cached serialization for this tick (or serialize if none yet). + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks. + // calls SerializeServer, so this function is to be called on server. + internal NetworkIdentitySerialization GetServerSerializationAtTick(int tick) + { + // only rebuild serialization once per tick. reuse otherwise. + // except for tests, where Time.frameCount never increases. + // so during tests, we always rebuild. + // (otherwise [SyncVar] changes would never be serialized in tests) + // + // NOTE: != instead of < because int.max+1 overflows at some point. + if (lastSerialization.tick != tick +#if UNITY_EDITOR + || !Application.isPlaying +#endif + ) + { + // reset + lastSerialization.ResetWriters(); + + // serialize + SerializeServer(false, + lastSerialization.ownerWriter, + lastSerialization.observersWriter); + + // set tick + lastSerialization.tick = tick; + //Debug.Log($"{name} (netId={netId}) serialized for tick={tickTimeStamp}"); + } + + // return it + return lastSerialization; + } + + internal void AddObserver(NetworkConnectionToClient conn) + { + if (observers.ContainsKey(conn.connectionId)) + { + // if we try to add a connectionId that was already added, then + // we may have generated one that was already in use. + return; + } + + // Debug.Log($"Added observer: {conn.address} added for {gameObject}"); + + // if we previously had no observers, then clear all dirty bits once. + // a monster's health may have changed while it had no observers. + // but that change (= the dirty bits) don't matter as soon as the + // first observer comes. + // -> first observer gets full spawn packet + // -> afterwards it gets delta packet + // => if we don't clear previous dirty bits, observer would get + // the health change because the bit was still set. + // => ultimately this happens because spawn doesn't reset dirty + // bits + // => which happens because spawn happens separately, instead of + // in Broadcast() (which will be changed in the future) + // + // NOTE that NetworkServer.Broadcast previously cleared dirty bits + // for ALL SPAWNED that don't have observers. that was super + // expensive. doing it when adding the first observer has the + // same result, without the O(N) iteration in Broadcast(). + // + // TODO remove this after moving spawning into Broadcast()! + if (observers.Count == 0) + { + ClearAllComponentsDirtyBits(); + } + + observers[conn.connectionId] = conn; + conn.AddToObserving(this); + } + + // clear all component's dirty bits no matter what + internal void ClearAllComponentsDirtyBits() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + comp.ClearAllDirtyBits(); + } + } + + // this is used when a connection is destroyed, since the "observers" property is read-only + internal void RemoveObserver(NetworkConnectionToClient conn) + { + observers.Remove(conn.connectionId); + } + + /// Assign control of an object to a client via the client's NetworkConnection. + // This causes hasAuthority to be set on the client that owns the object, + // and NetworkBehaviour.OnStartAuthority will be called on that client. + // This object then will be in the NetworkConnection.clientOwnedObjects + // list for the connection. + // + // Authority can be removed with RemoveClientAuthority. Only one client + // can own an object at any time. This does not need to be called for + // player objects, as their authority is setup automatically. + public bool AssignClientAuthority(NetworkConnectionToClient conn) + { + if (!isServer) + { + Debug.LogError("AssignClientAuthority can only be called on the server for spawned objects."); + return false; + } + + if (conn == null) + { + Debug.LogError($"AssignClientAuthority for {gameObject} owner cannot be null. Use RemoveClientAuthority() instead."); + return false; + } + + if (connectionToClient != null && conn != connectionToClient) + { + Debug.LogError($"AssignClientAuthority for {gameObject} already has an owner. Use RemoveClientAuthority() first."); + return false; + } + + SetClientOwner(conn); + + // The client will match to the existing object + NetworkServer.SendChangeOwnerMessage(this, conn); + + clientAuthorityCallback?.Invoke(conn, this, true); + + return true; + } + + // used when adding players + internal void SetClientOwner(NetworkConnectionToClient conn) + { + // do nothing if it already has an owner + if (connectionToClient != null && conn != connectionToClient) + { + Debug.LogError($"Object {this} netId={netId} already has an owner. Use RemoveClientAuthority() first", this); + return; + } + + // otherwise set the owner connection + connectionToClient = conn; + } + + /// Removes ownership for an object. + // Applies to objects that had authority set by AssignClientAuthority, + // or NetworkServer.Spawn with a NetworkConnection parameter included. + // Authority cannot be removed for player objects. + public void RemoveClientAuthority() + { + if (!isServer) + { + Debug.LogError("RemoveClientAuthority can only be called on the server for spawned objects."); + return; + } + + if (connectionToClient?.identity == this) + { + Debug.LogError("RemoveClientAuthority cannot remove authority for a player object"); + return; + } + + if (connectionToClient != null) + { + clientAuthorityCallback?.Invoke(connectionToClient, this, false); + NetworkConnectionToClient previousOwner = connectionToClient; + connectionToClient = null; + NetworkServer.SendChangeOwnerMessage(this, previousOwner); + } + } + + // Reset is called when the user hits the Reset button in the + // Inspector's context menu or when adding the component the first time. + // This function is only called in editor mode. + // + // Reset() seems to be called only for Scene objects. + // we can't destroy them (they are always in the scene). + // instead we disable them and call Reset(). + // + // Do not reset SyncObjects from Reset + // - Unspawned objects need to retain their list contents + // - They may be respawned, especially players, but others as well. + // + // OLD COMMENT: + // Marks the identity for future reset, this is because we cant reset + // the identity during destroy as people might want to be able to read + // the members inside OnDestroy(), and we have no way of invoking reset + // after OnDestroy is called. + internal void ResetState() + { + hasSpawned = false; + clientStarted = false; + isClient = false; + isServer = false; + //isLocalPlayer = false; <- cleared AFTER ClearLocalPlayer below! + + // remove authority flag. This object may be unspawned, not destroyed, on client. + isOwned = false; + NotifyAuthority(); + + netId = 0; + connectionToServer = null; + connectionToClient = null; + + ClearObservers(); + + // clear local player if it was the local player, + // THEN reset isLocalPlayer AFTERWARDS + if (isLocalPlayer) + { + // only clear NetworkClient.localPlayer IF IT POINTS TO US! + // see OnDestroy() comments. it does the same. + // (https://github.com/vis2k/Mirror/issues/2635) + if (NetworkClient.localPlayer == this) + NetworkClient.localPlayer = null; + } + + previousLocalPlayer = null; + isLocalPlayer = false; + } + + bool hadAuthority; + internal void NotifyAuthority() + { + if (!hadAuthority && isOwned) + OnStartAuthority(); + if (hadAuthority && !isOwned) + OnStopAuthority(); + hadAuthority = isOwned; + } + + internal void OnStartAuthority() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStartAuthority should be caught, so that one + // component's exception doesn't stop all other components from + // being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStartAuthority(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + internal void OnStopAuthority() + { + foreach (NetworkBehaviour comp in NetworkBehaviours) + { + // an exception in OnStopAuthority should be caught, so that one + // component's exception doesn't stop all other components from + // being initialized + // => this is what Unity does for Start() etc. too. + // one exception doesn't stop all the other Start() calls! + try + { + comp.OnStopAuthority(); + } + catch (Exception e) + { + Debug.LogException(e, comp); + } + } + } + + // Called when NetworkIdentity is destroyed + internal void ClearObservers() + { + foreach (NetworkConnectionToClient conn in observers.Values) + { + conn.RemoveFromObserving(this, true); + } + observers.Clear(); + } + } +} diff --git a/Assets/Mirror/Core/NetworkIdentity.cs.meta b/Assets/Mirror/Core/NetworkIdentity.cs.meta new file mode 100644 index 0000000..2ca784b --- /dev/null +++ b/Assets/Mirror/Core/NetworkIdentity.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9b91ecbcc199f4492b9a91e820070131 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkIdentity.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkLoop.cs b/Assets/Mirror/Core/NetworkLoop.cs new file mode 100644 index 0000000..a9cd490 --- /dev/null +++ b/Assets/Mirror/Core/NetworkLoop.cs @@ -0,0 +1,211 @@ +// our ideal update looks like this: +// transport.process_incoming() +// update_world() +// transport.process_outgoing() +// +// this way we avoid unnecessary latency for low-ish server tick rates. +// for example, if we were to use this tick: +// transport.process_incoming/outgoing() +// update_world() +// +// then anything sent in update_world wouldn't be actually sent out by the +// transport until the next frame. if server runs at 60Hz, then this can add +// 16ms latency for every single packet. +// +// => instead we process incoming, update world, process_outgoing in the same +// frame. it's more clear (no race conditions) and lower latency. +// => we need to add custom Update functions to the Unity engine: +// NetworkEarlyUpdate before Update()/FixedUpdate() +// NetworkLateUpdate after LateUpdate() +// this way the user can update the world in Update/FixedUpdate/LateUpdate +// and networking still runs before/after those functions no matter what! +// => see also: https://docs.unity3d.com/Manual/ExecutionOrder.html +// => update order: +// * we add to the end of EarlyUpdate so it runs after any Unity initializations +// * we add to the end of PreLateUpdate so it runs after LateUpdate(). adding +// to the beginning of PostLateUpdate doesn't actually work. +using System; +using UnityEngine; +using UnityEngine.LowLevel; +using UnityEngine.PlayerLoop; + +namespace Mirror +{ + public static class NetworkLoop + { + // helper enum to add loop to begin/end of subSystemList + internal enum AddMode { Beginning, End } + + // callbacks for others to hook into if they need Early/LateUpdate. + public static Action OnEarlyUpdate; + public static Action OnLateUpdate; + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void ResetStatics() + { + OnEarlyUpdate = null; + OnLateUpdate = null; + } + + // helper function to find an update function's index in a player loop + // type. this is used for testing to guarantee our functions are added + // at the beginning/end properly. + internal static int FindPlayerLoopEntryIndex(PlayerLoopSystem.UpdateFunction function, PlayerLoopSystem playerLoop, Type playerLoopSystemType) + { + // did we find the type? e.g. EarlyUpdate/PreLateUpdate/etc. + if (playerLoop.type == playerLoopSystemType) + return Array.FindIndex(playerLoop.subSystemList, (elem => elem.updateDelegate == function)); + + // recursively keep looking + if (playerLoop.subSystemList != null) + { + for (int i = 0; i < playerLoop.subSystemList.Length; ++i) + { + int index = FindPlayerLoopEntryIndex(function, playerLoop.subSystemList[i], playerLoopSystemType); + if (index != -1) return index; + } + } + return -1; + } + + // MODIFIED AddSystemToPlayerLoopList from Unity.Entities.ScriptBehaviourUpdateOrder (ECS) + // + // => adds an update function to the Unity internal update type. + // => Unity has different update loops: + // https://medium.com/@thebeardphantom/unity-2018-and-playerloop-5c46a12a677 + // EarlyUpdate + // FixedUpdate + // PreUpdate + // Update + // PreLateUpdate + // PostLateUpdate + // + // function: the custom update function to add + // IMPORTANT: according to a comment in Unity.Entities.ScriptBehaviourUpdateOrder, + // the UpdateFunction can not be virtual because + // Mono 4.6 has problems invoking virtual methods + // as delegates from native! + // ownerType: the .type to fill in so it's obvious who the new function + // belongs to. seems to be mostly for debugging. pass any. + // addMode: prepend or append to update list + internal static bool AddToPlayerLoop(PlayerLoopSystem.UpdateFunction function, Type ownerType, ref PlayerLoopSystem playerLoop, Type playerLoopSystemType, AddMode addMode) + { + // did we find the type? e.g. EarlyUpdate/PreLateUpdate/etc. + if (playerLoop.type == playerLoopSystemType) + { + // debugging + //Debug.Log($"Found playerLoop of type {playerLoop.type} with {playerLoop.subSystemList.Length} Functions:"); + //foreach (PlayerLoopSystem sys in playerLoop.subSystemList) + // Debug.Log($" ->{sys.type}"); + + // make sure the function wasn't added yet. + // with domain reload disabled, it would otherwise be added twice: + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3392 + if (Array.FindIndex(playerLoop.subSystemList, (s => s.updateDelegate == function)) != -1) + { + // loop contains the function, so return true. + return true; + } + + // resize & expand subSystemList to fit one more entry + int oldListLength = (playerLoop.subSystemList != null) ? playerLoop.subSystemList.Length : 0; + Array.Resize(ref playerLoop.subSystemList, oldListLength + 1); + + // IMPORTANT: always insert a FRESH PlayerLoopSystem! + // We CAN NOT resize and then OVERWRITE an entry's type/loop. + // => PlayerLoopSystem has native IntPtr loop members + // => forgetting to clear those would cause undefined behaviour! + // see also: https://github.com/vis2k/Mirror/pull/2652 + PlayerLoopSystem system = new PlayerLoopSystem { + type = ownerType, + updateDelegate = function + }; + + // prepend our custom loop to the beginning + if (addMode == AddMode.Beginning) + { + // shift to the right, write into first array element + Array.Copy(playerLoop.subSystemList, 0, playerLoop.subSystemList, 1, playerLoop.subSystemList.Length - 1); + playerLoop.subSystemList[0] = system; + } + // append our custom loop to the end + else if (addMode == AddMode.End) + { + // simply write into last array element + playerLoop.subSystemList[oldListLength] = system; + } + + // debugging + //Debug.Log($"New playerLoop of type {playerLoop.type} with {playerLoop.subSystemList.Length} Functions:"); + //foreach (PlayerLoopSystem sys in playerLoop.subSystemList) + // Debug.Log($" ->{sys.type}"); + + return true; + } + + // recursively keep looking + if (playerLoop.subSystemList != null) + { + for (int i = 0; i < playerLoop.subSystemList.Length; ++i) + { + if (AddToPlayerLoop(function, ownerType, ref playerLoop.subSystemList[i], playerLoopSystemType, addMode)) + return true; + } + } + return false; + } + + // hook into Unity runtime to actually add our custom functions + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void RuntimeInitializeOnLoad() + { + //Debug.Log("Mirror: adding Network[Early/Late]Update to Unity..."); + + // get loop + // 2019 has GetCURRENTPlayerLoop which is safe to use without + // breaking other custom system's custom loops. + // see also: https://github.com/vis2k/Mirror/pull/2627/files + PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop(); + + // add NetworkEarlyUpdate to the end of EarlyUpdate so it runs after + // any Unity initializations but before the first Update/FixedUpdate + AddToPlayerLoop(NetworkEarlyUpdate, typeof(NetworkLoop), ref playerLoop, typeof(EarlyUpdate), AddMode.End); + + // add NetworkLateUpdate to the end of PreLateUpdate so it runs after + // LateUpdate(). adding to the beginning of PostLateUpdate doesn't + // actually work. + AddToPlayerLoop(NetworkLateUpdate, typeof(NetworkLoop), ref playerLoop, typeof(PreLateUpdate), AddMode.End); + + // set the new loop + PlayerLoop.SetPlayerLoop(playerLoop); + } + + static void NetworkEarlyUpdate() + { + // loop functions run in edit mode and in play mode. + // however, we only want to call NetworkServer/Client in play mode. + if (!Application.isPlaying) return; + + NetworkTime.EarlyUpdate(); + //Debug.Log($"NetworkEarlyUpdate {Time.time}"); + NetworkServer.NetworkEarlyUpdate(); + NetworkClient.NetworkEarlyUpdate(); + // invoke event after mirror has done it's early updating. + OnEarlyUpdate?.Invoke(); + } + + static void NetworkLateUpdate() + { + // loop functions run in edit mode and in play mode. + // however, we only want to call NetworkServer/Client in play mode. + if (!Application.isPlaying) return; + + //Debug.Log($"NetworkLateUpdate {Time.time}"); + // invoke event before mirror does its final late updating. + OnLateUpdate?.Invoke(); + NetworkServer.NetworkLateUpdate(); + NetworkClient.NetworkLateUpdate(); + } + } +} diff --git a/Assets/Mirror/Core/NetworkLoop.cs.meta b/Assets/Mirror/Core/NetworkLoop.cs.meta new file mode 100644 index 0000000..522313b --- /dev/null +++ b/Assets/Mirror/Core/NetworkLoop.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2c6cec4e279774b919386e05545317b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkLoop.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkManager.cs b/Assets/Mirror/Core/NetworkManager.cs new file mode 100644 index 0000000..ed0494d --- /dev/null +++ b/Assets/Mirror/Core/NetworkManager.cs @@ -0,0 +1,1452 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.Serialization; + +namespace Mirror +{ + public enum PlayerSpawnMethod { Random, RoundRobin } + public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host } + public enum HeadlessStartOptions { DoNothing, AutoStartServer, AutoStartClient } + + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Manager")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-manager")] + public class NetworkManager : MonoBehaviour + { + /// Enable to keep NetworkManager alive when changing scenes. + // This should be set if your game has a single NetworkManager that exists for the lifetime of the process. If there is a NetworkManager in each scene, then this should not be set. + [Header("Configuration")] + [FormerlySerializedAs("m_DontDestroyOnLoad")] + [Tooltip("Should the Network Manager object be persisted through scene changes?")] + public bool dontDestroyOnLoad = true; + + /// Multiplayer games should always run in the background so the network doesn't time out. + [FormerlySerializedAs("m_RunInBackground")] + [Tooltip("Multiplayer games should always run in the background so the network doesn't time out.")] + public bool runInBackground = true; + + /// Should the server auto-start when 'Server Build' is checked in build settings + [Header("Auto-Start Options")] + + [Tooltip("Choose whether Server or Client should auto-start in headless builds")] + public HeadlessStartOptions headlessStartMode = HeadlessStartOptions.DoNothing; + + [Tooltip("Headless Start Mode in Editor\nwhen enabled, headless start mode will be used in editor as well.")] + public bool editorAutoStart; + + /// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. + [Tooltip("Server / Client send rate per second.\nUse 60-100Hz for fast paced games like Counter-Strike to minimize latency.\nUse around 30Hz for games like WoW to minimize computations.\nUse around 1-10Hz for slow paced games like EVE.")] + [FormerlySerializedAs("serverTickRate")] + public int sendRate = 60; + + // client send rate follows server send rate to avoid errors for now + /// Client Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. + // [Tooltip("Client broadcasts 'sendRate' times per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")] + // public int clientSendRate = 30; // 33 ms + + /// Automatically switch to this scene upon going offline (on start / on disconnect / on shutdown). + [Header("Scene Management")] + [Scene] + [FormerlySerializedAs("m_OfflineScene")] + [Tooltip("Scene that Mirror will switch to when the client or server is stopped")] + public string offlineScene = ""; + + /// Automatically switch to this scene upon going online (after connect/startserver). + [Scene] + [FormerlySerializedAs("m_OnlineScene")] + [Tooltip("Scene that Mirror will switch to when the server is started. Clients will recieve a Scene Message to load the server's current scene when they connect.")] + public string onlineScene = ""; + + [Range(0, 60), Tooltip("Optional delay that can be used after disconnecting to show a 'Connection lost...' message or similar before loading the offline scene, which may take a long time in big projects.")] + public float offlineSceneLoadDelay = 0; + + // transport layer + [Header("Network Info")] + [Tooltip("Transport component attached to this object that server and client will use to connect")] + public Transport transport; + + /// Server's address for clients to connect to. + [FormerlySerializedAs("m_NetworkAddress")] + [Tooltip("Network Address where the client should connect to the server. Server does not use this for anything.")] + public string networkAddress = "localhost"; + + /// The maximum number of concurrent network connections to support. + [FormerlySerializedAs("m_MaxConnections")] + [Tooltip("Maximum number of concurrent connections.")] + public int maxConnections = 100; + + // Mirror global disconnect inactive option, independent of Transport. + // not all Transports do this properly, and it's easiest to configure this just once. + // this is very useful for some projects, keep it. + [Tooltip("When enabled, the server automatically disconnects inactive connections after the configured timeout.")] + public bool disconnectInactiveConnections; + + [Tooltip("Timeout in seconds for server to automatically disconnect inactive connections if 'disconnectInactiveConnections' is enabled.")] + public float disconnectInactiveTimeout = 60f; + + [Header("Authentication")] + [Tooltip("Authentication component attached to this object")] + public NetworkAuthenticator authenticator; + + /// The default prefab to be used to create player objects on the server. + // Player objects are created in the default handler for AddPlayer() on + // the server. Implementing OnServerAddPlayer overrides this behaviour. + [Header("Player Object")] + [FormerlySerializedAs("m_PlayerPrefab")] + [Tooltip("Prefab of the player object. Prefab must have a Network Identity component. May be an empty game object or a full avatar.")] + public GameObject playerPrefab; + + /// Enable to automatically create player objects on connect and on scene change. + [FormerlySerializedAs("m_AutoCreatePlayer")] + [Tooltip("Should Mirror automatically spawn the player after scene change?")] + public bool autoCreatePlayer = true; + + /// Where to spawn players. + [FormerlySerializedAs("m_PlayerSpawnMethod")] + [Tooltip("Round Robin or Random order of Start Position selection")] + public PlayerSpawnMethod playerSpawnMethod; + + /// Prefabs that can be spawned over the network need to be registered here. + [FormerlySerializedAs("m_SpawnPrefabs"), HideInInspector] + public List spawnPrefabs = new List(); + + /// List of transforms populated by NetworkStartPositions + public static List startPositions = new List(); + public static int startPositionIndex; + + [Header("Security")] + [Tooltip("For security, it is recommended to disconnect a player if a networked action triggers an exception\nThis could prevent components being accessed in an undefined state, which may be an attack vector for exploits.\nHowever, some games may want to allow exceptions in order to not interrupt the player's experience.")] + public bool exceptionsDisconnect = true; // security by default + + [Header("Snapshot Interpolation")] + public SnapshotInterpolationSettings snapshotSettings = new SnapshotInterpolationSettings(); + + [Header("Connection Quality")] + [Tooltip("Method to use for connection quality evaluation.\nSimple: based on rtt and jitter.\nPragmatic: based on snapshot interpolation adjustment.")] + public ConnectionQualityMethod evaluationMethod; + + [Tooltip("Interval in seconds to evaluate connection quality.\nSet to 0 to disable connection quality evaluation.")] + [Range(0, 60)] + [FormerlySerializedAs("connectionQualityInterval")] + public float evaluationInterval = 3; + + [Header("Interpolation UI - Requires Editor / Dev Build")] + public bool timeInterpolationGui = false; + + /// The one and only NetworkManager + public static NetworkManager singleton { get; internal set; } + + /// Number of active player objects across all connections on the server. + public int numPlayers => NetworkServer.connections.Count(kv => kv.Value.identity != null); + + /// True if the server is running or client is connected/connecting. + public bool isNetworkActive => NetworkServer.active || NetworkClient.active; + + // TODO remove this + // internal for tests + internal static NetworkConnection clientReadyConnection; + + /// True if the client loaded a new scene when connecting to the server. + // This is set before OnClientConnect is called, so it can be checked + // there to perform different logic if a scene load occurred. + protected bool clientLoadedScene; + + // helper enum to know if we started the networkmanager as server/client/host. + // -> this is necessary because when StartHost changes server scene to + // online scene, FinishLoadScene is called and the host client isn't + // connected yet (no need to connect it before server was fully set up). + // in other words, we need this to know which mode we are running in + // during FinishLoadScene. + public NetworkManagerMode mode { get; private set; } + + // virtual so that inheriting classes' OnValidate() can call base.OnValidate() too + public virtual void OnValidate() + { + // always >= 0 + maxConnections = Mathf.Max(maxConnections, 0); + + if (playerPrefab != null && !playerPrefab.TryGetComponent(out NetworkIdentity _)) + { + Debug.LogError("NetworkManager - Player Prefab must have a NetworkIdentity."); + playerPrefab = null; + } + + // This avoids the mysterious "Replacing existing prefab with assetId ... Old prefab 'Player', New prefab 'Player'" warning. + if (playerPrefab != null && spawnPrefabs.Contains(playerPrefab)) + { + Debug.LogWarning("NetworkManager - Player Prefab doesn't need to be in Spawnable Prefabs list too. Removing it."); + spawnPrefabs.Remove(playerPrefab); + } + } + + // virtual so that inheriting classes' Reset() can call base.Reset() too + // Reset only gets called when the component is added or the user resets the component + // Thats why we validate these things that only need to be validated on adding the NetworkManager here + // If we would do it in OnValidate() then it would run this everytime a value changes + public virtual void Reset() + { + // make sure someone doesn't accidentally add another NetworkManager + // need transform.root because when adding to a child, the parent's + // Reset isn't called. + foreach (NetworkManager manager in transform.root.GetComponentsInChildren()) + { + if (manager != this) + { + Debug.LogError($"{name} detected another component of type {typeof(NetworkManager)} in its hierarchy on {manager.name}. There can only be one, please remove one of them."); + // return early so that transport component isn't auto-added + // to the duplicate NetworkManager. + return; + } + } + } + + // virtual so that inheriting classes' Awake() can call base.Awake() too + public virtual void Awake() + { + // Don't allow collision-destroyed second instance to continue. + if (!InitializeSingleton()) return; + + // Apply configuration in Awake once already + ApplyConfiguration(); + + // Set the networkSceneName to prevent a scene reload + // if client connection to server fails. + networkSceneName = offlineScene; + + // setup OnSceneLoaded callback + SceneManager.sceneLoaded += OnSceneLoaded; + } + + // virtual so that inheriting classes' Start() can call base.Start() too + public virtual void Start() + { + // Auto-start headless server or client. + // + // We can't do this in Awake because Awake is for initialization + // and some transports might not be ready until Start. + // + // Auto-starting in Editor is useful for debugging, so that can + // be enabled with editorAutoStart. + if (Utils.IsHeadless()) + { + if (!Application.isEditor || editorAutoStart) + switch (headlessStartMode) + { + case HeadlessStartOptions.AutoStartServer: + StartServer(); + break; + case HeadlessStartOptions.AutoStartClient: + StartClient(); + break; + } + } + } + + // make sure to call base.Update() when overwriting + public virtual void Update() + { + ApplyConfiguration(); + } + + // virtual so that inheriting classes' LateUpdate() can call base.LateUpdate() too + public virtual void LateUpdate() + { + UpdateScene(); + } + + //////////////////////////////////////////////////////////////////////// + + // keep the online scene change check in a separate function. + // only change scene if the requested online scene is not blank, and is not already loaded. + bool IsServerOnlineSceneChangeNeeded() => + !string.IsNullOrWhiteSpace(onlineScene) && + !Utils.IsSceneActive(onlineScene) && + onlineScene != offlineScene; + + // NetworkManager exposes some NetworkServer/Client configuration. + // we apply it every Update() in order to avoid two sources of truth. + // fixes issues where NetworkServer.sendRate was never set because + // NetworkManager.StartServer was never called, etc. + // => all exposed settings should be applied at all times if NM exists. + void ApplyConfiguration() + { + NetworkServer.tickRate = sendRate; + NetworkClient.snapshotSettings = snapshotSettings; + NetworkClient.connectionQualityInterval = evaluationInterval; + NetworkClient.connectionQualityMethod = evaluationMethod; + } + + // full server setup code, without spawning objects yet + void SetupServer() + { + // Debug.Log("NetworkManager SetupServer"); + InitializeSingleton(); + + // apply settings before initializing anything + NetworkServer.disconnectInactiveConnections = disconnectInactiveConnections; + NetworkServer.disconnectInactiveTimeout = disconnectInactiveTimeout; + NetworkServer.exceptionsDisconnect = exceptionsDisconnect; + + if (runInBackground) + Application.runInBackground = true; + + if (authenticator != null) + { + authenticator.OnStartServer(); + authenticator.OnServerAuthenticated.AddListener(OnServerAuthenticated); + } + + ConfigureHeadlessFrameRate(); + + // start listening to network connections + NetworkServer.Listen(maxConnections); + + // this must be after Listen(), since that registers the default message handlers + RegisterServerMessages(); + + // do not call OnStartServer here yet. + // this is up to the caller. different for server-only vs. host mode. + } + + /// Starts the server, listening for incoming connections. + public void StartServer() + { + if (NetworkServer.active) + { + Debug.LogWarning("Server already started."); + return; + } + + mode = NetworkManagerMode.ServerOnly; + + // StartServer is inherently ASYNCHRONOUS (=doesn't finish immediately) + // + // Here is what it does: + // Listen + // if onlineScene: + // LoadSceneAsync + // ... + // FinishLoadSceneServerOnly + // SpawnObjects + // else: + // SpawnObjects + // + // there is NO WAY to make it synchronous because both LoadSceneAsync + // and LoadScene do not finish loading immediately. as long as we + // have the onlineScene feature, it will be asynchronous! + + SetupServer(); + + // call OnStartServer AFTER Listen, so that NetworkServer.active is + // true and we can call NetworkServer.Spawn in OnStartServer + // overrides. + // (useful for loading & spawning stuff from database etc.) + // + // note: there is no risk of someone connecting after Listen() and + // before OnStartServer() because this all runs in one thread + // and we don't start processing connects until Update. + OnStartServer(); + + // scene change needed? then change scene and spawn afterwards. + if (IsServerOnlineSceneChangeNeeded()) + { + ServerChangeScene(onlineScene); + } + // otherwise spawn directly + else + { + NetworkServer.SpawnObjects(); + } + } + + void SetupClient() + { + InitializeSingleton(); + + // apply settings before initializing anything + NetworkClient.exceptionsDisconnect = exceptionsDisconnect; + // NetworkClient.sendRate = clientSendRate; + + if (runInBackground) + Application.runInBackground = true; + + if (authenticator != null) + { + authenticator.OnStartClient(); + authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated); + } + + } + + /// Starts the client, connects it to the server with networkAddress. + public void StartClient() + { + // Do checks and short circuits before setting anything up. + // If / when we retry, we won't have conflict issues. + if (NetworkClient.active) + { + Debug.LogWarning("Client already started."); + return; + } + + if (string.IsNullOrWhiteSpace(networkAddress)) + { + Debug.LogError("Must set the Network Address field in the manager"); + return; + } + + mode = NetworkManagerMode.ClientOnly; + + SetupClient(); + + // In case this is a headless client... + ConfigureHeadlessFrameRate(); + + RegisterClientMessages(); + + NetworkClient.Connect(networkAddress); + + OnStartClient(); + } + + /// Starts the client, connects it to the server via Uri + public void StartClient(Uri uri) + { + if (NetworkClient.active) + { + Debug.LogWarning("Client already started."); + return; + } + + mode = NetworkManagerMode.ClientOnly; + + SetupClient(); + + RegisterClientMessages(); + + // Debug.Log($"NetworkManager StartClient address:{uri}"); + networkAddress = uri.Host; + + NetworkClient.Connect(uri); + + OnStartClient(); + } + + /// Starts a network "host" - a server and client in the same application. + public void StartHost() + { + if (NetworkServer.active || NetworkClient.active) + { + Debug.LogWarning("Server or Client already started."); + return; + } + + mode = NetworkManagerMode.Host; + + // StartHost is inherently ASYNCHRONOUS (=doesn't finish immediately) + // + // Here is what it does: + // Listen + // ConnectHost + // if onlineScene: + // LoadSceneAsync + // ... + // FinishLoadSceneHost + // FinishStartHost + // SpawnObjects + // StartHostClient <= not guaranteed to happen after SpawnObjects if onlineScene is set! + // ClientAuth + // success: server sends changescene msg to client + // else: + // FinishStartHost + // + // there is NO WAY to make it synchronous because both LoadSceneAsync + // and LoadScene do not finish loading immediately. as long as we + // have the onlineScene feature, it will be asynchronous! + + // setup server first + SetupServer(); + + // scene change needed? then change scene and spawn afterwards. + // => BEFORE host client connects. if client auth succeeds then the + // server tells it to load 'onlineScene'. we can't do that if + // server is still in 'offlineScene'. so load on server first. + if (IsServerOnlineSceneChangeNeeded()) + { + // call FinishStartHost after changing scene. + finishStartHostPending = true; + ServerChangeScene(onlineScene); + } + // otherwise call FinishStartHost directly + else + { + FinishStartHost(); + } + } + + // This may be set true in StartHost and is evaluated in FinishStartHost + bool finishStartHostPending; + + // FinishStartHost is guaranteed to be called after the host server was + // fully started and all the asynchronous StartHost magic is finished + // (= scene loading), or immediately if there was no asynchronous magic. + // + // note: we don't really need FinishStartClient/FinishStartServer. the + // host version is enough. + void FinishStartHost() + { + // ConnectHost needs to be called BEFORE SpawnObjects: + // https://github.com/vis2k/Mirror/pull/1249/ + // -> this sets NetworkServer.localConnection. + // -> localConnection needs to be set before SpawnObjects because: + // -> SpawnObjects calls OnStartServer in all NetworkBehaviours + // -> OnStartServer might spawn an object and set [SyncVar(hook="OnColorChanged")] object.color = green; + // -> this calls SyncVar.set (generated by Weaver), which has + // a custom case for host mode (because host mode doesn't + // get OnDeserialize calls, where SyncVar hooks are usually + // called): + // + // if (!SyncVarEqual(value, ref color)) + // { + // if (NetworkServer.localClientActive && !getSyncVarHookGuard(1uL)) + // { + // setSyncVarHookGuard(1uL, value: true); + // OnColorChangedHook(value); + // setSyncVarHookGuard(1uL, value: false); + // } + // SetSyncVar(value, ref color, 1uL); + // } + // + // -> localClientActive needs to be true, otherwise the hook + // isn't called in host mode! + // + // TODO call this after spawnobjects and worry about the syncvar hook fix later? + NetworkClient.ConnectHost(); + + // invoke user callbacks AFTER ConnectHost has set .activeHost. + // this way initialization can properly handle host mode. + // + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3302 + // where [SyncVar] hooks wouldn't be called for objects spawned in + // NetworkManager.OnStartServer, because .activeHost was still false. + // + // TODO is there a risk of someone connecting between Listen() and FinishStartHost()? + OnStartServer(); + + // call OnStartHost AFTER SetupServer. this way we can use + // NetworkServer.Spawn etc. in there too. just like OnStartServer + // is called after the server is actually properly started. + OnStartHost(); + + // server scene was loaded. now spawn all the objects + NetworkServer.SpawnObjects(); + + // connect client and call OnStartClient AFTER server scene was + // loaded and all objects were spawned. + // DO NOT do this earlier. it would cause race conditions where a + // client will do things before the server is even fully started. + //Debug.Log("StartHostClient called"); + SetupClient(); + RegisterClientMessages(); + + // InvokeOnConnected needs to be called AFTER RegisterClientMessages + // (https://github.com/vis2k/Mirror/pull/1249/) + HostMode.InvokeOnConnected(); + + OnStartClient(); + } + + /// This stops both the client and the server that the manager is using. + public void StopHost() + { + OnStopHost(); + StopClient(); + StopServer(); + } + + /// Stops the server from listening and simulating the game. + public void StopServer() + { + // return if already stopped to avoid recursion deadlock + if (!NetworkServer.active) + return; + + if (authenticator != null) + { + authenticator.OnServerAuthenticated.RemoveListener(OnServerAuthenticated); + authenticator.OnStopServer(); + } + + // Get Network Manager out of DDOL before going to offline scene + // to avoid collision and let a fresh Network Manager be created. + // IMPORTANT: .gameObject can be null if StopClient is called from + // OnApplicationQuit or from tests! + if (gameObject != null + && gameObject.scene.name == "DontDestroyOnLoad" + && !string.IsNullOrWhiteSpace(offlineScene) + && SceneManager.GetActiveScene().path != offlineScene) + SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene()); + + OnStopServer(); + + //Debug.Log("NetworkManager StopServer"); + NetworkServer.Shutdown(); + + // set offline mode BEFORE changing scene so that FinishStartScene + // doesn't think we need initialize anything. + mode = NetworkManagerMode.Offline; + + if (!string.IsNullOrWhiteSpace(offlineScene)) + { + ServerChangeScene(offlineScene); + } + + startPositionIndex = 0; + + networkSceneName = ""; + } + + /// Stops and disconnects the client. + public void StopClient() + { + if (mode == NetworkManagerMode.Offline) + return; + + // For Host client, call OnServerDisconnect before NetworkClient.Disconnect + // because we need NetworkServer.localConnection to not be null + // NetworkClient.Disconnect will set it null. + if (mode == NetworkManagerMode.Host) + OnServerDisconnect(NetworkServer.localConnection); + + // ask client -> transport to disconnect. + // handle voluntary and involuntary disconnects in OnClientDisconnect. + // + // StopClient + // NetworkClient.Disconnect + // Transport.Disconnect + // ... + // Transport.OnClientDisconnect + // NetworkClient.OnTransportDisconnect + // NetworkManager.OnClientDisconnect + NetworkClient.Disconnect(); + } + + // called when quitting the application by closing the window / pressing + // stop in the editor. virtual so that inheriting classes' + // OnApplicationQuit() can call base.OnApplicationQuit() too + // (this can't be in OnDestroy: https://github.com/MirrorNetworking/Mirror/issues/3952) + public virtual void OnApplicationQuit() + { + // stop client first + // (we want to send the quit packet to the server instead of waiting + // for a timeout) + if (NetworkClient.isConnected) + { + StopClient(); + //Debug.Log("OnApplicationQuit: stopped client"); + } + + // stop server after stopping client (for proper host mode stopping) + if (NetworkServer.active) + { + StopServer(); + //Debug.Log("OnApplicationQuit: stopped server"); + } + + // Call ResetStatics to reset statics and singleton + ResetStatics(); + } + + /// Set the frame rate for a headless builds. Override to disable or modify. + // useful for dedicated servers. + // useful for headless benchmark clients. + public virtual void ConfigureHeadlessFrameRate() + { + if (Utils.IsHeadless()) + { + Application.targetFrameRate = sendRate; + // Debug.Log($"Server Tick Rate set to {Application.targetFrameRate} Hz."); + } + } + + bool InitializeSingleton() + { + if (singleton != null && singleton == this) + return true; + + if (dontDestroyOnLoad) + { + if (singleton != null) + { + Debug.LogWarning("Multiple NetworkManagers detected in the scene. Only one NetworkManager can exist at a time. The duplicate NetworkManager will be destroyed."); + Destroy(gameObject); + + // Return false to not allow collision-destroyed second instance to continue. + return false; + } + //Debug.Log("NetworkManager created singleton (DontDestroyOnLoad)"); + singleton = this; + if (Application.isPlaying) + { + // Force the object to scene root, in case user made it a child of something + // in the scene since DDOL is only allowed for scene root objects + transform.SetParent(null); + DontDestroyOnLoad(gameObject); + } + } + else + { + //Debug.Log("NetworkManager created singleton (ForScene)"); + singleton = this; + } + + // set active transport AFTER setting singleton. + // so only if we didn't destroy ourselves. + + // This tries to avoid missing transport errors and more clearly tells user what to fix. + if (transport == null) + if (TryGetComponent(out Transport newTransport)) + { + Debug.LogWarning($"No Transport assigned to Network Manager - Using {newTransport} found on same object."); + transport = newTransport; + } + else + { + Debug.LogError("No Transport on Network Manager...add a transport and assign it."); + return false; + } + + Transport.active = transport; + return true; + } + + void RegisterServerMessages() + { + NetworkServer.OnConnectedEvent = OnServerConnectInternal; + NetworkServer.OnDisconnectedEvent = OnServerDisconnect; + NetworkServer.OnErrorEvent = OnServerError; + NetworkServer.OnTransportExceptionEvent = OnServerTransportException; + NetworkServer.RegisterHandler(OnServerAddPlayerInternal); + + // Network Server initially registers its own handler for this, so we replace it here. + NetworkServer.ReplaceHandler(OnServerReadyMessageInternal); + } + + void RegisterClientMessages() + { + NetworkClient.OnConnectedEvent = OnClientConnectInternal; + NetworkClient.OnDisconnectedEvent = OnClientDisconnectInternal; + NetworkClient.OnErrorEvent = OnClientError; + NetworkClient.OnTransportExceptionEvent = OnClientTransportException; + + // Don't require authentication because server may send NotReadyMessage from ServerChangeScene + NetworkClient.RegisterHandler(OnClientNotReadyMessageInternal, false); + NetworkClient.RegisterHandler(OnClientSceneInternal, false); + + if (playerPrefab != null) + NetworkClient.RegisterPrefab(playerPrefab); + + foreach (GameObject prefab in spawnPrefabs.Where(t => t != null)) + NetworkClient.RegisterPrefab(prefab); + } + + // This is the only way to clear the singleton, so another instance can be created. + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + public static void ResetStatics() + { + // call StopHost if we have a singleton + if (singleton) + singleton.StopHost(); + + // reset all statics + startPositions.Clear(); + startPositionIndex = 0; + clientReadyConnection = null; + loadingSceneAsync = null; + networkSceneName = string.Empty; + + // and finally (in case it isn't null already)... + singleton = null; + } + + // virtual so that inheriting classes' OnDestroy() can call base.OnDestroy() too + public virtual void OnDestroy() + { + //Debug.Log("NetworkManager destroyed"); + } + + /// The name of the current network scene. + // set by NetworkManager when changing the scene. + // new clients will automatically load this scene. + // Loading a scene manually won't set it. + public static string networkSceneName { get; protected set; } = ""; + + public static AsyncOperation loadingSceneAsync; + + /// Change the server scene and all client's scenes across the network. + // Called automatically if onlineScene or offlineScene are set, but it + // can be called from user code to switch scenes again while the game is + // in progress. This automatically sets clients to be not-ready during + // the change and ready again to participate in the new scene. + public virtual void ServerChangeScene(string newSceneName) + { + if (string.IsNullOrWhiteSpace(newSceneName)) + { + Debug.LogError("ServerChangeScene empty scene name"); + return; + } + + if (NetworkServer.isLoadingScene && newSceneName == networkSceneName) + { + Debug.LogError($"Scene change is already in progress for {newSceneName}"); + return; + } + + // Throw error if called from client + // Allow changing scene while stopping the server + if (!NetworkServer.active && newSceneName != offlineScene) + { + Debug.LogError("ServerChangeScene can only be called on an active server."); + return; + } + + // Debug.Log($"ServerChangeScene {newSceneName}"); + NetworkServer.SetAllClientsNotReady(); + networkSceneName = newSceneName; + + // Let server prepare for scene change + OnServerChangeScene(newSceneName); + + // set server flag to stop processing messages while changing scenes + // it will be re-enabled in FinishLoadScene. + NetworkServer.isLoadingScene = true; + + loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName); + + // ServerChangeScene can be called when stopping the server + // when this happens the server is not active so does not need to tell clients about the change + if (NetworkServer.active) + { + // notify all clients about the new scene + NetworkServer.SendToAll(new SceneMessage + { + sceneName = newSceneName + }); + } + + startPositionIndex = 0; + startPositions.Clear(); + } + + // This is only set in ClientChangeScene below...never on server. + // We need to check this in OnClientSceneChanged called from FinishLoadSceneClientOnly + // to prevent AddPlayer message after loading/unloading additive scenes + SceneOperation clientSceneOperation = SceneOperation.Normal; + + internal void ClientChangeScene(string newSceneName, SceneOperation sceneOperation = SceneOperation.Normal, bool customHandling = false) + { + if (string.IsNullOrWhiteSpace(newSceneName)) + { + Debug.LogError("ClientChangeScene empty scene name"); + return; + } + + //Debug.Log($"ClientChangeScene newSceneName: {newSceneName} networkSceneName{networkSceneName}"); + + // Let client prepare for scene change + OnClientChangeScene(newSceneName, sceneOperation, customHandling); + + // After calling OnClientChangeScene, exit if server since server is already doing + // the actual scene change, and we don't need to do it for the host client + if (NetworkServer.active) + return; + + // set client flag to stop processing messages while loading scenes. + // otherwise we would process messages and then lose all the state + // as soon as the load is finishing, causing all kinds of bugs + // because of missing state. + // (client may be null after StopClient etc.) + // Debug.Log("ClientChangeScene: pausing handlers while scene is loading to avoid data loss after scene was loaded."); + NetworkClient.isLoadingScene = true; + + // Cache sceneOperation so we know what was requested by the + // Scene message in OnClientChangeScene and OnClientSceneChanged + clientSceneOperation = sceneOperation; + + // scene handling will happen in overrides of OnClientChangeScene and/or OnClientSceneChanged + // Do not call FinishLoadScene here. Custom handler will assign loadingSceneAsync and we need + // to wait for that to finish. UpdateScene already checks for that to be not null and isDone. + if (customHandling) + return; + + switch (sceneOperation) + { + case SceneOperation.Normal: + loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName); + break; + case SceneOperation.LoadAdditive: + // Ensure additive scene is not already loaded on client by name or path + // since we don't know which was passed in the Scene message + if (!SceneManager.GetSceneByName(newSceneName).IsValid() && !SceneManager.GetSceneByPath(newSceneName).IsValid()) + loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName, LoadSceneMode.Additive); + else + { + Debug.LogWarning($"Scene {newSceneName} is already loaded"); + + // Reset the flag that we disabled before entering this switch + NetworkClient.isLoadingScene = false; + } + break; + case SceneOperation.UnloadAdditive: + // Ensure additive scene is actually loaded on client by name or path + // since we don't know which was passed in the Scene message + if (SceneManager.GetSceneByName(newSceneName).IsValid() || SceneManager.GetSceneByPath(newSceneName).IsValid()) + loadingSceneAsync = SceneManager.UnloadSceneAsync(newSceneName, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects); + else + { + Debug.LogWarning($"Cannot unload {newSceneName} with UnloadAdditive operation"); + + // Reset the flag that we disabled before entering this switch + NetworkClient.isLoadingScene = false; + } + break; + } + + // don't change the client's current networkSceneName when loading additive scene content + if (sceneOperation == SceneOperation.Normal) + networkSceneName = newSceneName; + } + + // support additive scene loads: + // NetworkScenePostProcess disables all scene objects on load, and + // * NetworkServer.SpawnObjects enables them again on the server when + // calling OnStartServer + // * NetworkClient.PrepareToSpawnSceneObjects enables them again on the + // client after the server sends ObjectSpawnStartedMessage to client + // in SpawnObserversForConnection. this is only called when the + // client joins, so we need to rebuild scene objects manually again + // TODO merge this with FinishLoadScene()? + void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + if (mode == LoadSceneMode.Additive) + { + if (NetworkServer.active) + { + // TODO only respawn the server objects from that scene later! + NetworkServer.SpawnObjects(); + // Debug.Log($"Respawned Server objects after additive scene load: {scene.name}"); + } + if (NetworkClient.active) + { + NetworkClient.PrepareToSpawnSceneObjects(); + // Debug.Log($"Rebuild Client spawnableObjects after additive scene load: {scene.name}"); + } + } + } + + void UpdateScene() + { + if (loadingSceneAsync != null && loadingSceneAsync.isDone) + { + //Debug.Log($"ClientChangeScene done readyConn {clientReadyConnection}"); + + // try-finally to guarantee loadingSceneAsync being cleared. + // fixes https://github.com/vis2k/Mirror/issues/2517 where if + // FinishLoadScene throws an exception, loadingSceneAsync would + // never be cleared and this code would run every Update. + try + { + FinishLoadScene(); + } + finally + { + loadingSceneAsync.allowSceneActivation = true; + loadingSceneAsync = null; + } + } + } + + protected void FinishLoadScene() + { + // NOTE: this cannot use NetworkClient.allClients[0] - that client may be for a completely different purpose. + + // process queued messages that we received while loading the scene + //Debug.Log("FinishLoadScene: resuming handlers after scene was loading."); + NetworkServer.isLoadingScene = false; + NetworkClient.isLoadingScene = false; + + // host mode? + if (mode == NetworkManagerMode.Host) + { + FinishLoadSceneHost(); + } + // server-only mode? + else if (mode == NetworkManagerMode.ServerOnly) + { + FinishLoadSceneServerOnly(); + } + // client-only mode? + else if (mode == NetworkManagerMode.ClientOnly) + { + FinishLoadSceneClientOnly(); + } + // otherwise we called it after stopping when loading offline scene. + // do nothing then. + } + + // finish load scene part for host mode. makes code easier and is + // necessary for FinishStartHost later. + // (the 3 things have to happen in that exact order) + void FinishLoadSceneHost() + { + // debug message is very important. if we ever break anything then + // it's very obvious to notice. + //Debug.Log("Finished loading scene in host mode."); + + if (clientReadyConnection != null) + { + clientLoadedScene = true; + clientReadyConnection = null; + } + + // do we need to finish a StartHost() call? + // then call FinishStartHost and let it take care of spawning etc. + if (finishStartHostPending) + { + finishStartHostPending = false; + FinishStartHost(); + + // call OnServerSceneChanged + OnServerSceneChanged(networkSceneName); + + // DO NOT call OnClientSceneChanged here. + // the scene change happened because StartHost loaded the + // server's online scene. it has nothing to do with the client. + // this was not meant as a client scene load, so don't call it. + // + // otherwise AddPlayer would be called twice: + // -> once for client OnConnected + // -> once in OnClientSceneChanged + } + // otherwise we just changed a scene in host mode + else + { + // spawn server objects + NetworkServer.SpawnObjects(); + + // call OnServerSceneChanged + OnServerSceneChanged(networkSceneName); + + if (NetworkClient.isConnected) + OnClientSceneChanged(); + } + } + + // finish load scene part for server-only. . makes code easier and is + // necessary for FinishStartServer later. + void FinishLoadSceneServerOnly() + { + // debug message is very important. if we ever break anything then + // it's very obvious to notice. + //Debug.Log("Finished loading scene in server-only mode."); + + NetworkServer.SpawnObjects(); + OnServerSceneChanged(networkSceneName); + } + + // finish load scene part for client-only. makes code easier and is + // necessary for FinishStartClient later. + void FinishLoadSceneClientOnly() + { + // debug message is very important. if we ever break anything then + // it's very obvious to notice. + //Debug.Log("Finished loading scene in client-only mode."); + + if (clientReadyConnection != null) + { + clientLoadedScene = true; + clientReadyConnection = null; + } + + if (NetworkClient.isConnected) + OnClientSceneChanged(); + } + + /// + /// Registers the transform of a game object as a player spawn location. + /// This is done automatically by NetworkStartPosition components, but can be done manually from user script code. + /// + /// Transform to register. + // Static because it's called from NetworkStartPosition::Awake + // and singleton may not exist yet + public static void RegisterStartPosition(Transform start) + { + // Debug.Log($"RegisterStartPosition: {start.gameObject.name} {start.position}"); + startPositions.Add(start); + + // reorder the list so that round-robin spawning uses the start positions + // in hierarchy order. This assumes all objects with NetworkStartPosition + // component are siblings, either in the scene root or together as children + // under a single parent in the scene. + startPositions = startPositions.OrderBy(transform => transform.GetSiblingIndex()).ToList(); + } + + /// Unregister a Transform from start positions. + // Static because it's called from NetworkStartPosition::OnDestroy + // and singleton may not exist yet + public static void UnRegisterStartPosition(Transform start) + { + //Debug.Log($"UnRegisterStartPosition: {start.name} {start.position}"); + startPositions.Remove(start); + } + + /// Get the next NetworkStartPosition based on the selected PlayerSpawnMethod. + public virtual Transform GetStartPosition() + { + // first remove any dead transforms + startPositions.RemoveAll(t => t == null); + + if (startPositions.Count == 0) + return null; + + if (playerSpawnMethod == PlayerSpawnMethod.Random) + { + return startPositions[UnityEngine.Random.Range(0, startPositions.Count)]; + } + else + { + Transform startPosition = startPositions[startPositionIndex]; + startPositionIndex = (startPositionIndex + 1) % startPositions.Count; + return startPosition; + } + } + + void OnServerConnectInternal(NetworkConnectionToClient conn) + { + //Debug.Log("NetworkManager.OnServerConnectInternal"); + + if (authenticator != null) + { + // we have an authenticator - let it handle authentication + authenticator.OnServerAuthenticate(conn); + } + else + { + // authenticate immediately + OnServerAuthenticated(conn); + } + } + + // called after successful authentication + // TODO do the NetworkServer.OnAuthenticated thing from x branch + void OnServerAuthenticated(NetworkConnectionToClient conn) + { + //Debug.Log("NetworkManager.OnServerAuthenticated"); + + // set connection to authenticated + conn.isAuthenticated = true; + + // proceed with the login handshake by calling OnServerConnect + if (networkSceneName != "" && networkSceneName != offlineScene) + { + SceneMessage msg = new SceneMessage() + { + sceneName = networkSceneName + }; + conn.Send(msg); + } + + OnServerConnect(conn); + } + + void OnServerReadyMessageInternal(NetworkConnectionToClient conn, ReadyMessage msg) + { + //Debug.Log("NetworkManager.OnServerReadyMessageInternal"); + OnServerReady(conn); + } + + void OnServerAddPlayerInternal(NetworkConnectionToClient conn, AddPlayerMessage msg) + { + //Debug.Log("NetworkManager.OnServerAddPlayer"); + + if (autoCreatePlayer && playerPrefab == null) + { + Debug.LogError("The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object."); + return; + } + + if (autoCreatePlayer && !playerPrefab.TryGetComponent(out NetworkIdentity _)) + { + Debug.LogError("The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab."); + return; + } + + if (conn.identity != null) + { + Debug.LogError("There is already a player for this connection."); + return; + } + + OnServerAddPlayer(conn); + } + + void OnClientConnectInternal() + { + //Debug.Log("NetworkManager.OnClientConnectInternal"); + + if (authenticator != null) + { + // we have an authenticator - let it handle authentication + authenticator.OnClientAuthenticate(); + } + else + { + // authenticate immediately + OnClientAuthenticated(); + } + } + + // called after successful authentication + void OnClientAuthenticated() + { + //Debug.Log("NetworkManager.OnClientAuthenticated"); + + // set connection to authenticated + NetworkClient.connection.isAuthenticated = true; + + // Set flag to wait for scene change? + if (string.IsNullOrWhiteSpace(onlineScene) || onlineScene == offlineScene || Utils.IsSceneActive(onlineScene)) + { + clientLoadedScene = false; + } + else + { + // Scene message expected from server. + clientLoadedScene = true; + clientReadyConnection = NetworkClient.connection; + } + + // Call virtual method regardless of whether a scene change is expected or not. + OnClientConnect(); + } + + // Transport callback, invoked after client fully disconnected. + // the call order should always be: + // Disconnect() -> ask Transport -> Transport.OnDisconnected -> Cleanup + void OnClientDisconnectInternal() + { + //Debug.Log("NetworkManager.OnClientDisconnectInternal"); + + // Only let this run once. StopClient in Host mode changes to ServerOnly + if (mode == NetworkManagerMode.ServerOnly || mode == NetworkManagerMode.Offline) + return; + + // user callback + OnClientDisconnect(); + + if (authenticator != null) + { + authenticator.OnClientAuthenticated.RemoveListener(OnClientAuthenticated); + authenticator.OnStopClient(); + } + + // set mode BEFORE changing scene so FinishStartScene doesn't re-initialize anything. + // set mode BEFORE NetworkClient.Disconnect so StopClient only runs once. + // set mode BEFORE OnStopClient so StopClient only runs once. + // If we got here from StopClient in Host mode, change to ServerOnly. + // - If StopHost was called, StopServer will put us in Offline mode. + if (mode == NetworkManagerMode.Host) + mode = NetworkManagerMode.ServerOnly; + else + mode = NetworkManagerMode.Offline; + + //Debug.Log("NetworkManager StopClient"); + OnStopClient(); + + // shutdown client + NetworkClient.Shutdown(); + + // Exit here if we're now in ServerOnly mode (StopClient called in Host mode). + if (mode == NetworkManagerMode.ServerOnly) return; + + // Get Network Manager out of DDOL before going to offline scene + // to avoid collision and let a fresh Network Manager be created. + // IMPORTANT: .gameObject can be null if StopClient is called from + // OnApplicationQuit or from tests! + if (gameObject != null + && gameObject.scene.name == "DontDestroyOnLoad" + && !string.IsNullOrWhiteSpace(offlineScene) + && SceneManager.GetActiveScene().path != offlineScene) + SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene()); + + // If StopHost called in Host mode, StopServer will change scenes after this. + // Check loadingSceneAsync to ensure we don't double-invoke the scene change. + // Check if NetworkServer.active because we can get here via Disconnect before server has started to change scenes. + if (!string.IsNullOrWhiteSpace(offlineScene) && !Utils.IsSceneActive(offlineScene) && loadingSceneAsync == null && !NetworkServer.active) + Invoke(nameof(ClientChangeOfflineScene), offlineSceneLoadDelay); + + networkSceneName = ""; + } + + // wrap ClientChangeScene call without parameters for use in Invoke. + void ClientChangeOfflineScene() => + ClientChangeScene(offlineScene, SceneOperation.Normal); + + void OnClientNotReadyMessageInternal(NotReadyMessage msg) + { + //Debug.Log("NetworkManager.OnClientNotReadyMessageInternal"); + NetworkClient.ready = false; + OnClientNotReady(); + + // NOTE: clientReadyConnection is not set here! don't want OnClientConnect to be invoked again after scene changes. + } + + void OnClientSceneInternal(SceneMessage msg) + { + //Debug.Log("NetworkManager.OnClientSceneInternal"); + + // This needs to run for host client too. NetworkServer.active is checked there + if (NetworkClient.isConnected) + ClientChangeScene(msg.sceneName, msg.sceneOperation, msg.customHandling); + } + + /// Called on the server when a new client connects. + public virtual void OnServerConnect(NetworkConnectionToClient conn) { } + + /// Called on the server when a client disconnects. + // Called by NetworkServer.OnTransportDisconnect! + public virtual void OnServerDisconnect(NetworkConnectionToClient conn) + { + // by default, this function destroys the connection's player. + // can be overwritten for cases like delayed logouts in MMOs to + // avoid players escaping from PvP situations by logging out. + NetworkServer.DestroyPlayerForConnection(conn); + //Debug.Log("OnServerDisconnect: Client disconnected."); + } + + /// Called on the server when a client is ready (= loaded the scene) + public virtual void OnServerReady(NetworkConnectionToClient conn) + { + if (conn.identity == null) + { + // this is now allowed (was not for a while) + //Debug.Log("Ready with no player object"); + } + NetworkServer.SetClientReady(conn); + } + + /// Called on server when a client requests to add the player. Adds playerPrefab by default. Can be overwritten. + // The default implementation for this function creates a new player object from the playerPrefab. + public virtual void OnServerAddPlayer(NetworkConnectionToClient conn) + { + Transform startPos = GetStartPosition(); + GameObject player = startPos != null + ? Instantiate(playerPrefab, startPos.position, startPos.rotation) + : Instantiate(playerPrefab); + + // instantiating a "Player" prefab gives it the name "Player(clone)" + // => appending the connectionId is WAY more useful for debugging! + player.name = $"{playerPrefab.name} [connId={conn.connectionId}]"; + NetworkServer.AddPlayerForConnection(conn, player); + } + + /// Called on server when transport raises an exception. NetworkConnection may be null. + public virtual void OnServerError(NetworkConnectionToClient conn, TransportError error, string reason) { } + + /// Called on server when transport raises an exception. NetworkConnection may be null. + public virtual void OnServerTransportException(NetworkConnectionToClient conn, Exception exception) { } + + /// Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed + public virtual void OnServerChangeScene(string newSceneName) { } + + /// Called on server after a scene load with ServerChangeScene() is completed. + public virtual void OnServerSceneChanged(string sceneName) { } + + /// Called on the client when connected to a server. By default it sets client as ready and adds a player. + public virtual void OnClientConnect() + { + // OnClientConnect by default calls AddPlayer but it should not do + // that when we have online/offline scenes. so we need the + // clientLoadedScene flag to prevent it. + if (!clientLoadedScene) + { + // Ready/AddPlayer is usually triggered by a scene load completing. + // if no scene was loaded, then Ready/AddPlayer it here instead. + if (!NetworkClient.ready) + NetworkClient.Ready(); + + if (autoCreatePlayer) + NetworkClient.AddPlayer(); + } + } + + /// Called on clients when disconnected from a server. + public virtual void OnClientDisconnect() { } + + /// Called on client when transport raises an exception. + public virtual void OnClientError(TransportError error, string reason) { } + + /// Called on client when transport raises an exception. + public virtual void OnClientTransportException(Exception exception) { } + + /// Called on clients when a servers tells the client it is no longer ready, e.g. when switching scenes. + public virtual void OnClientNotReady() { } + + /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed + // customHandling: indicates if scene loading will be handled through overrides + public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) { } + + /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. + // Scene changes can cause player objects to be destroyed. The default + // implementation of OnClientSceneChanged in the NetworkManager is to + // add a player object for the connection if no player object exists. + public virtual void OnClientSceneChanged() + { + // always become ready. + if (NetworkClient.connection.isAuthenticated && !NetworkClient.ready) NetworkClient.Ready(); + + // Only call AddPlayer for normal scene changes, not additive load/unload + if (NetworkClient.connection.isAuthenticated && clientSceneOperation == SceneOperation.Normal && autoCreatePlayer && NetworkClient.localPlayer == null) + { + // add player if existing one is null + NetworkClient.AddPlayer(); + } + } + + // Since there are multiple versions of StartServer, StartClient and + // StartHost, to reliably customize their functionality, users would + // need override all the versions. Instead these callbacks are invoked + // from all versions, so users only need to implement this one case. + + /// This is invoked when a host is started. + public virtual void OnStartHost() { } + + /// This is invoked when a server is started - including when a host is started. + public virtual void OnStartServer() { } + + /// This is invoked when the client is started. + public virtual void OnStartClient() { } + + /// This is called when a server is stopped - including when a host is stopped. + public virtual void OnStopServer() { } + + /// This is called when a client is stopped. + public virtual void OnStopClient() { } + + /// This is called when a host is stopped. + public virtual void OnStopHost() { } + +#if DEBUG + // keep OnGUI even in builds. useful to debug snap interp. + void OnGUI() + { + if (!timeInterpolationGui) return; + NetworkClient.OnGUI(); + } +#endif + } +} diff --git a/Assets/Mirror/Core/NetworkManager.cs.meta b/Assets/Mirror/Core/NetworkManager.cs.meta new file mode 100644 index 0000000..6e81bbe --- /dev/null +++ b/Assets/Mirror/Core/NetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkManagerHUD.cs b/Assets/Mirror/Core/NetworkManagerHUD.cs new file mode 100644 index 0000000..f78eede --- /dev/null +++ b/Assets/Mirror/Core/NetworkManagerHUD.cs @@ -0,0 +1,162 @@ +using UnityEngine; + +namespace Mirror +{ + /// Shows NetworkManager controls in a GUI at runtime. + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Manager HUD")] + [RequireComponent(typeof(NetworkManager))] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-manager-hud")] + public class NetworkManagerHUD : MonoBehaviour + { + NetworkManager manager; + + public int offsetX; + public int offsetY; + + void Awake() + { + manager = GetComponent(); + } + + void OnGUI() + { + // If this width is changed, also change offsetX in GUIConsole::OnGUI + int width = 300; + + GUILayout.BeginArea(new Rect(10 + offsetX, 40 + offsetY, width, 9999)); + + if (!NetworkClient.isConnected && !NetworkServer.active) + StartButtons(); + else + StatusLabels(); + + if (NetworkClient.isConnected && !NetworkClient.ready) + { + if (GUILayout.Button("Client Ready")) + { + // client ready + NetworkClient.Ready(); + if (NetworkClient.localPlayer == null) + NetworkClient.AddPlayer(); + } + } + + StopButtons(); + + GUILayout.EndArea(); + } + + void StartButtons() + { + if (!NetworkClient.active) + { +#if UNITY_WEBGL + // cant be a server in webgl build + if (GUILayout.Button("Single Player")) + { + NetworkServer.listen = false; + manager.StartHost(); + } +#else + // Server + Client + if (GUILayout.Button("Host (Server + Client)")) + manager.StartHost(); +#endif + + // Client + IP (+ PORT) + GUILayout.BeginHorizontal(); + + if (GUILayout.Button("Client")) + manager.StartClient(); + + manager.networkAddress = GUILayout.TextField(manager.networkAddress); + // only show a port field if we have a port transport + // we can't have "IP:PORT" in the address field since this only + // works for IPV4:PORT. + // for IPV6:PORT it would be misleading since IPV6 contains ":": + // 2001:0db8:0000:0000:0000:ff00:0042:8329 + if (Transport.active is PortTransport portTransport) + { + // use TryParse in case someone tries to enter non-numeric characters + if (ushort.TryParse(GUILayout.TextField(portTransport.Port.ToString()), out ushort port)) + portTransport.Port = port; + } + + GUILayout.EndHorizontal(); + + // Server Only +#if UNITY_WEBGL + // cant be a server in webgl build + GUILayout.Box("( WebGL cannot be server )"); +#else + if (GUILayout.Button("Server Only")) + manager.StartServer(); +#endif + } + else + { + // Connecting + GUILayout.Label($"Connecting to {manager.networkAddress}.."); + if (GUILayout.Button("Cancel Connection Attempt")) + manager.StopClient(); + } + } + + void StatusLabels() + { + // host mode + // display separately because this always confused people: + // Server: ... + // Client: ... + if (NetworkServer.active && NetworkClient.active) + { + // host mode + GUILayout.Label($"Host: running via {Transport.active}"); + } + else if (NetworkServer.active) + { + // server only + GUILayout.Label($"Server: running via {Transport.active}"); + } + else if (NetworkClient.isConnected) + { + // client only + GUILayout.Label($"Client: connected to {manager.networkAddress} via {Transport.active}"); + } + } + + void StopButtons() + { + if (NetworkServer.active && NetworkClient.isConnected) + { + GUILayout.BeginHorizontal(); +#if UNITY_WEBGL + if (GUILayout.Button("Stop Single Player")) + manager.StopHost(); +#else + // stop host if host mode + if (GUILayout.Button("Stop Host")) + manager.StopHost(); + + // stop client if host mode, leaving server up + if (GUILayout.Button("Stop Client")) + manager.StopClient(); +#endif + GUILayout.EndHorizontal(); + } + else if (NetworkClient.isConnected) + { + // stop client if client-only + if (GUILayout.Button("Stop Client")) + manager.StopClient(); + } + else if (NetworkServer.active) + { + // stop server if server-only + if (GUILayout.Button("Stop Server")) + manager.StopServer(); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkManagerHUD.cs.meta b/Assets/Mirror/Core/NetworkManagerHUD.cs.meta new file mode 100644 index 0000000..fb72f54 --- /dev/null +++ b/Assets/Mirror/Core/NetworkManagerHUD.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6442dc8070ceb41f094e44de0bf87274 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkManagerHUD.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkMessage.cs b/Assets/Mirror/Core/NetworkMessage.cs new file mode 100644 index 0000000..7fc387a --- /dev/null +++ b/Assets/Mirror/Core/NetworkMessage.cs @@ -0,0 +1,4 @@ +namespace Mirror +{ + public interface NetworkMessage {} +} diff --git a/Assets/Mirror/Core/NetworkMessage.cs.meta b/Assets/Mirror/Core/NetworkMessage.cs.meta new file mode 100644 index 0000000..3afc348 --- /dev/null +++ b/Assets/Mirror/Core/NetworkMessage.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: eb04e4848a2e4452aa2dbd7adb801c51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkMessage.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkMessages.cs b/Assets/Mirror/Core/NetworkMessages.cs new file mode 100644 index 0000000..7a70d94 --- /dev/null +++ b/Assets/Mirror/Core/NetworkMessages.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using UnityEngine; + +namespace Mirror +{ + // for performance, we (ab)use c# generics to cache the message id in a static field + // this is significantly faster than doing the computation at runtime or looking up cached results via Dictionary + // generic classes have separate static fields per type specification + public static class NetworkMessageId where T : struct, NetworkMessage + { + // automated message id from type hash. + // platform independent via stable hashcode. + // => convenient so we don't need to track messageIds across projects + // => addons can work with each other without knowing their ids before + // => 2 bytes is enough to avoid collisions. + // registering a messageId twice will log a warning anyway. + public static readonly ushort Id = CalculateId(); + + // Gets the 32bit fnv1a hash + // To get it down to 16bit but still reduce hash collisions we cant just cast it to ushort + // Instead we take the highest 16bits of the 32bit hash and fold them with xor into the lower 16bits + // This will create a more uniform 16bit hash, the method is described in: + // http://www.isthe.com/chongo/tech/comp/fnv/ in section "Changing the FNV hash size - xor-folding" + static ushort CalculateId() => typeof(T).FullName.GetStableHashCode16(); + } + + // message packing all in one place, instead of constructing headers in all + // kinds of different places + // + // MsgType (2 bytes) + // Content (ContentSize bytes) + public static class NetworkMessages + { + // size of message id header in bytes + public const int IdSize = sizeof(ushort); + + // Id <> Type lookup for debugging, profiler, etc. + // important when debugging messageId errors! + public static readonly Dictionary Lookup = + new Dictionary(); + + // dump all types for debugging + public static void LogTypes() + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine("NetworkMessageIds:"); + foreach (KeyValuePair kvp in Lookup) + { + builder.AppendLine($" Id={kvp.Key} = {kvp.Value}"); + } + Debug.Log(builder.ToString()); + } + + // max message content size (without header) calculation for convenience + // -> Transport.GetMaxPacketSize is the raw maximum + // -> Every message gets serialized into <> + // -> Every serialized message get put into a batch with one timestamp per batch + // -> Every message in a batch has a varuint size header. + // use the worst case VarUInt size for the largest possible + // message size = int.max. + public static int MaxContentSize(int channelId) + { + // calculate the max possible size that can fit in a batch + int transportMax = Transport.active.GetMaxPacketSize(channelId); + return transportMax - IdSize - Batcher.MaxMessageOverhead(transportMax); + } + + // max message size which includes header + content. + public static int MaxMessageSize(int channelId) => + MaxContentSize(channelId) + IdSize; + + // automated message id from type hash. + // platform independent via stable hashcode. + // => convenient so we don't need to track messageIds across projects + // => addons can work with each other without knowing their ids before + // => 2 bytes is enough to avoid collisions. + // registering a messageId twice will log a warning anyway. + // keep this for convenience. easier to use than NetworkMessageId.Id. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort GetId() where T : struct, NetworkMessage => + NetworkMessageId.Id; + + // pack message before sending + // -> NetworkWriter passed as arg so that we can use .ToArraySegment + // and do an allocation free send before recycling it. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Pack(T message, NetworkWriter writer) + where T : struct, NetworkMessage + { + writer.WriteUShort(NetworkMessageId.Id); + writer.Write(message); + } + + // read only the message id. + // common function in case we ever change the header size. + public static bool UnpackId(NetworkReader reader, out ushort messageId) + { + // read message type + try + { + messageId = reader.ReadUShort(); + return true; + } + catch (System.IO.EndOfStreamException) + { + messageId = 0; + return false; + } + } + + // version for handlers with channelId + // inline! only exists for 20-30 messages and they call it all the time. + internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication, bool exceptionsDisconnect) + where T : struct, NetworkMessage + where C : NetworkConnection + => (conn, reader, channelId) => + { + // protect against DOS attacks if attackers try to send invalid + // data packets to crash the server/client. there are a thousand + // ways to cause an exception in data handling: + // - invalid headers + // - invalid message ids + // - invalid data causing exceptions + // - negative ReadBytesAndSize prefixes + // - invalid utf8 strings + // - etc. + // + // let's catch them all and then disconnect that connection to avoid + // further attacks. + T message = default; + // record start position for NetworkDiagnostics because reader might contain multiple messages if using batching + int startPos = reader.Position; + try + { + if (requireAuthentication && !conn.isAuthenticated) + { + // message requires authentication, but the connection was not authenticated + Debug.LogWarning($"Disconnecting connection: {conn}. Received message {typeof(T)} that required authentication, but the user has not authenticated yet"); + conn.Disconnect(); + return; + } + + //Debug.Log($"ConnectionRecv {conn} msgType:{typeof(T)} content:{BitConverter.ToString(reader.buffer.Array, reader.buffer.Offset, reader.buffer.Count)}"); + + // if it is a value type, just use default(T) + // otherwise allocate a new instance + message = reader.Read(); + } + catch (Exception exception) + { + // should we disconnect on exceptions? + if (exceptionsDisconnect) + { + Debug.LogError($"Disconnecting connection: {conn} because reading a message of type {typeof(T)} caused an Exception. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}"); + conn.Disconnect(); + return; + } + // otherwise log it but allow the connection to keep playing + else + { + Debug.LogError($"Caught an Exception when reading a message from: {conn} of type {typeof(T)}. Reason: {exception}"); + return; + } + } + finally + { + int endPos = reader.Position; + // TODO: Figure out the correct channel + NetworkDiagnostics.OnReceive(message, channelId, endPos - startPos); + } + + // user handler exception should not stop the whole server + try + { + // user implemented handler + handler((C)conn, message, channelId); + } + catch (Exception exception) + { + // should we disconnect on exceptions? + if (exceptionsDisconnect) + { + Debug.LogError($"Disconnecting connection: {conn} because handling a message of type {typeof(T)} caused an Exception. This can happen if the other side accidentally (or an attacker intentionally) sent invalid data. Reason: {exception}"); + conn.Disconnect(); + } + // otherwise log it but allow the connection to keep playing + else + { + Debug.LogError($"Caught an Exception when handling a message from: {conn} of type {typeof(T)}. Reason: {exception}"); + } + } + }; + + // version for handlers without channelId + // TODO obsolete this some day to always use the channelId version. + // all handlers in this version are wrapped with 1 extra action. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static NetworkMessageDelegate WrapHandler(Action handler, bool requireAuthentication, bool exceptionsDisconnect) + where T : struct, NetworkMessage + where C : NetworkConnection + { + // wrap action as channelId version, call original + void Wrapped(C conn, T msg, int _) => handler(conn, msg); + return WrapHandler((Action)Wrapped, requireAuthentication, exceptionsDisconnect); + } + } +} diff --git a/Assets/Mirror/Core/NetworkMessages.cs.meta b/Assets/Mirror/Core/NetworkMessages.cs.meta new file mode 100644 index 0000000..d2600a3 --- /dev/null +++ b/Assets/Mirror/Core/NetworkMessages.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2db134099f0df4d96a84ae7a0cd9b4bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkMessages.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkReader.cs b/Assets/Mirror/Core/NetworkReader.cs new file mode 100644 index 0000000..82fb7cd --- /dev/null +++ b/Assets/Mirror/Core/NetworkReader.cs @@ -0,0 +1,249 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; + +namespace Mirror +{ + /// Network Reader for most simple types like floats, ints, buffers, structs, etc. Use NetworkReaderPool.GetReader() to avoid allocations. + // Note: This class is intended to be extremely pedantic, + // and throw exceptions whenever stuff is going slightly wrong. + // The exceptions will be handled in NetworkServer/NetworkClient. + // + // Note that NetworkWriter can be passed in constructor thanks to implicit + // ArraySegment conversion: + // NetworkReader reader = new NetworkReader(writer); + public class NetworkReader + { + // internal buffer + // byte[] pointer would work, but we use ArraySegment to also support + // the ArraySegment constructor + internal ArraySegment buffer; + + /// Next position to read from the buffer + // 'int' is the best type for .Position. 'short' is too small if we send >32kb which would result in negative .Position + // -> converting long to int is fine until 2GB of data (MAX_INT), so we don't have to worry about overflows here + public int Position; + + /// Remaining bytes that can be read, for convenience. + public int Remaining => buffer.Count - Position; + + /// Total buffer capacity, independent of reader position. + public int Capacity => buffer.Count; + + // cache encoding for ReadString instead of creating it with each time + // 1000 readers before: 1MB GC, 30ms + // 1000 readers after: 0.8MB GC, 18ms + // member(!) to avoid static state. + // + // throwOnInvalidBytes is true. + // if false, it would silently ignore the invalid bytes but continue + // with the valid ones, creating strings like "a�������". + // instead, we want to catch it manually and return String.Empty. + // this is safer. see test: ReadString_InvalidUTF8(). + internal readonly UTF8Encoding encoding = new UTF8Encoding(false, true); + + // while allocation free ReadArraySegment is encouraged, + // some functions can allocate a new byte[], List, Texture, etc. + // we should keep a reasonable allocation size limit: + // -> server won't accidentally allocate 2GB on a mobile device + // -> client won't allocate 2GB on server for ClientToServer [SyncVar]s + // -> unlike max string length of 64 KB, we need a larger limit here. + // large enough to not break existing projects, + // small enough to reasonably limit allocation attacks. + // -> we don't know the exact size of ReadList etc. because is + // managed. instead, this is considered a 'collection length' limit. + public const int AllocationLimit = 1024 * 1024 * 16; // 16 MB * sizeof(T) + + public NetworkReader(ArraySegment segment) + { + buffer = segment; + } + +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have the implicit byte[] to segment conversion yet + public NetworkReader(byte[] bytes) + { + buffer = new ArraySegment(bytes, 0, bytes.Length); + } +#endif + + // sometimes it's useful to point a reader on another buffer instead of + // allocating a new reader (e.g. NetworkReaderPool) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetBuffer(ArraySegment segment) + { + buffer = segment; + Position = 0; + } + +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have the implicit byte[] to segment conversion yet + public void SetBuffer(byte[] bytes) + { + buffer = new ArraySegment(bytes, 0, bytes.Length); + Position = 0; + } +#endif + + // ReadBlittable from DOTSNET + // this is extremely fast, but only works for blittable types. + // => private to make sure nobody accidentally uses it for non-blittable + // + // Benchmark: see NetworkWriter.WriteBlittable! + // + // Note: + // ReadBlittable assumes same endianness for server & client. + // All Unity 2018+ platforms are little endian. + // + // This is not safe to expose to random structs. + // * StructLayout.Sequential is the default, which is safe. + // if the struct contains a reference type, it is converted to Auto. + // but since all structs here are unmanaged blittable, it's safe. + // see also: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind?view=netframework-4.8#system-runtime-interopservices-layoutkind-sequential + // * StructLayout.Pack depends on CPU word size. + // this may be different 4 or 8 on some ARM systems, etc. + // this is not safe, and would cause bytes/shorts etc. to be padded. + // see also: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.structlayoutattribute.pack?view=net-6.0 + // * If we force pack all to '1', they would have no padding which is + // great for bandwidth. but on some android systems, CPU can't read + // unaligned memory. + // see also: https://github.com/vis2k/Mirror/issues/3044 + // * The only option would be to force explicit layout with multiples + // of word size. but this requires lots of weaver checking and is + // still questionable (IL2CPP etc.). + // + // Note: inlining ReadBlittable is enough. don't inline ReadInt etc. + // we don't want ReadBlittable to be copied in place everywhere. + internal unsafe T ReadBlittable() + where T : unmanaged + { + // check if blittable for safety +#if UNITY_EDITOR + if (!UnsafeUtility.IsBlittable(typeof(T))) + { + throw new ArgumentException($"{typeof(T)} is not blittable!"); + } +#endif + + // calculate size + // sizeof(T) gets the managed size at compile time. + // Marshal.SizeOf gets the unmanaged size at runtime (slow). + // => our 1mio writes benchmark is 6x slower with Marshal.SizeOf + // => for blittable types, sizeof(T) is even recommended: + // https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices + int size = sizeof(T); + + // ensure remaining + if (Remaining < size) + { + throw new EndOfStreamException($"ReadBlittable<{typeof(T)}> not enough data in buffer to read {size} bytes: {ToString()}"); + } + + // read blittable + T value; + fixed (byte* ptr = &buffer.Array[buffer.Offset + Position]) + { +#if UNITY_ANDROID + // on some android systems, reading *(T*)ptr throws a NRE if + // the ptr isn't aligned (i.e. if Position is 1,2,3,5, etc.). + // here we have to use memcpy. + // + // => we can't get a pointer of a struct in C# without + // marshalling allocations + // => instead, we stack allocate an array of type T and use that + // => stackalloc avoids GC and is very fast. it only works for + // value types, but all blittable types are anyway. + // + // this way, we can still support blittable reads on android. + // see also: https://github.com/vis2k/Mirror/issues/3044 + // (solution discovered by AIIO, FakeByte, mischa) + T* valueBuffer = stackalloc T[1]; + UnsafeUtility.MemCpy(valueBuffer, ptr, size); + value = valueBuffer[0]; +#else + // cast buffer to a T* pointer and then read from it. + value = *(T*)ptr; +#endif + } + Position += size; + return value; + } + + // blittable'?' template for code reuse + // note: bool isn't blittable. need to read as byte. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal T? ReadBlittableNullable() + where T : unmanaged => + ReadByte() != 0 ? ReadBlittable() : default(T?); + + public byte ReadByte() => ReadBlittable(); + + /// Read 'count' bytes into the bytes array + // NOTE: returns byte[] because all reader functions return something. + public byte[] ReadBytes(byte[] bytes, int count) + { + // user may call ReadBytes(ReadInt()). ensure positive count. + if (count < 0) throw new ArgumentOutOfRangeException("ReadBytes requires count >= 0"); + + // check if passed byte array is big enough + if (count > bytes.Length) + { + throw new EndOfStreamException($"ReadBytes can't read {count} + bytes because the passed byte[] only has length {bytes.Length}"); + } + // ensure remaining + if (Remaining < count) + { + throw new EndOfStreamException($"ReadBytesSegment can't read {count} bytes because it would read past the end of the stream. {ToString()}"); + } + + Array.Copy(buffer.Array, buffer.Offset + Position, bytes, 0, count); + Position += count; + return bytes; + } + + /// Read 'count' bytes allocation-free as ArraySegment that points to the internal array. + public ArraySegment ReadBytesSegment(int count) + { + // user may call ReadBytes(ReadInt()). ensure positive count. + if (count < 0) throw new ArgumentOutOfRangeException("ReadBytesSegment requires count >= 0"); + + // ensure remaining + if (Remaining < count) + { + throw new EndOfStreamException($"ReadBytesSegment can't read {count} bytes because it would read past the end of the stream. {ToString()}"); + } + + // return the segment + ArraySegment result = new ArraySegment(buffer.Array, buffer.Offset + Position, count); + Position += count; + return result; + } + + /// Reads any data type that mirror supports. Uses weaver populated Reader(T).read + public T Read() + { + Func readerDelegate = Reader.read; + if (readerDelegate == null) + { + Debug.LogError($"No reader found for {typeof(T)}. Use a type supported by Mirror or define a custom reader extension for {typeof(T)}."); + return default; + } + return readerDelegate(this); + } + + // print the full buffer with position / capacity. + public override string ToString() => + $"[{buffer.ToHexString()} @ {Position}/{Capacity}]"; + } + + /// Helper class that weaver populates with all reader types. + // Note that c# creates a different static variable for each type + // -> Weaver.ReaderWriterProcessor.InitializeReaderAndWriters() populates it + public static class Reader + { + public static Func read; + } +} diff --git a/Assets/Mirror/Core/NetworkReader.cs.meta b/Assets/Mirror/Core/NetworkReader.cs.meta new file mode 100644 index 0000000..f1bd5bd --- /dev/null +++ b/Assets/Mirror/Core/NetworkReader.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1610f05ec5bd14d6882e689f7372596a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkReader.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkReaderExtensions.cs b/Assets/Mirror/Core/NetworkReaderExtensions.cs new file mode 100644 index 0000000..dd366f6 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderExtensions.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace Mirror +{ + // Mirror's Weaver automatically detects all NetworkReader function types, + // but they do all need to be extensions. + public static class NetworkReaderExtensions + { + public static byte ReadByte(this NetworkReader reader) => reader.ReadBlittable(); + public static byte? ReadByteNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static sbyte ReadSByte(this NetworkReader reader) => reader.ReadBlittable(); + public static sbyte? ReadSByteNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + // bool is not blittable. read as ushort. + public static char ReadChar(this NetworkReader reader) => (char)reader.ReadBlittable(); + public static char? ReadCharNullable(this NetworkReader reader) => (char?)reader.ReadBlittableNullable(); + + // bool is not blittable. read as byte. + public static bool ReadBool(this NetworkReader reader) => reader.ReadBlittable() != 0; + public static bool? ReadBoolNullable(this NetworkReader reader) + { + byte? value = reader.ReadBlittableNullable(); + return value.HasValue ? (value.Value != 0) : default(bool?); + } + + public static short ReadShort(this NetworkReader reader) => (short)reader.ReadUShort(); + public static short? ReadShortNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static ushort ReadUShort(this NetworkReader reader) => reader.ReadBlittable(); + public static ushort? ReadUShortNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static int ReadInt(this NetworkReader reader) => reader.ReadBlittable(); + public static int? ReadIntNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static uint ReadUInt(this NetworkReader reader) => reader.ReadBlittable(); + public static uint? ReadUIntNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static long ReadLong(this NetworkReader reader) => reader.ReadBlittable(); + public static long? ReadLongNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static ulong ReadULong(this NetworkReader reader) => reader.ReadBlittable(); + public static ulong? ReadULongNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + // ReadInt/UInt/Long/ULong writes full bytes by default. + // define additional "VarInt" versions that Weaver will automatically prefer. + // 99% of the time [SyncVar] ints are small values, which makes this very much worth it. + [WeaverPriority] public static int ReadVarInt(this NetworkReader reader) => (int)Compression.DecompressVarInt(reader); + [WeaverPriority] public static uint ReadVarUInt(this NetworkReader reader) => (uint)Compression.DecompressVarUInt(reader); + [WeaverPriority] public static long ReadVarLong(this NetworkReader reader) => Compression.DecompressVarInt(reader); + [WeaverPriority] public static ulong ReadVarULong(this NetworkReader reader) => Compression.DecompressVarUInt(reader); + + public static float ReadFloat(this NetworkReader reader) => reader.ReadBlittable(); + public static float? ReadFloatNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static double ReadDouble(this NetworkReader reader) => reader.ReadBlittable(); + public static double? ReadDoubleNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static decimal ReadDecimal(this NetworkReader reader) => reader.ReadBlittable(); + public static decimal? ReadDecimalNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Half ReadHalf(this NetworkReader reader) => new Half(reader.ReadUShort()); + + /// if an invalid utf8 string is sent + public static string ReadString(this NetworkReader reader) + { + // read number of bytes + ushort size = reader.ReadUShort(); + + // null support, see NetworkWriter + if (size == 0) + return null; + + ushort realSize = (ushort)(size - 1); + + // make sure it's within limits to avoid allocation attacks etc. + if (realSize > NetworkWriter.MaxStringLength) + throw new EndOfStreamException($"NetworkReader.ReadString - Value too long: {realSize} bytes. Limit is: {NetworkWriter.MaxStringLength} bytes"); + + ArraySegment data = reader.ReadBytesSegment(realSize); + + // convert directly from buffer to string via encoding + // throws in case of invalid utf8. + // see test: ReadString_InvalidUTF8() + return reader.encoding.GetString(data.Array, data.Offset, data.Count); + } + + public static byte[] ReadBytes(this NetworkReader reader, int count) + { + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (count > NetworkReader.AllocationLimit) + { + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate {count} bytes, which is larger than the allowed limit of {NetworkReader.AllocationLimit} bytes."); + } + + byte[] bytes = new byte[count]; + reader.ReadBytes(bytes, count); + return bytes; + } + + /// if count is invalid + public static byte[] ReadBytesAndSize(this NetworkReader reader) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + + // most sizes are small, read size as VarUInt! + uint count = (uint)Compression.DecompressVarUInt(reader); + // uint count = reader.ReadUInt(); + // Use checked() to force it to throw OverflowException if data is invalid + return count == 0 ? null : reader.ReadBytes(checked((int)(count - 1u))); + } + // Reads ArraySegment and size header + /// if count is invalid + public static ArraySegment ReadArraySegmentAndSize(this NetworkReader reader) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + + // most sizes are small, read size as VarUInt! + uint count = (uint)Compression.DecompressVarUInt(reader); + // uint count = reader.ReadUInt(); + // Use checked() to force it to throw OverflowException if data is invalid + return count == 0 ? default : reader.ReadBytesSegment(checked((int)(count - 1u))); + } + + public static Vector2 ReadVector2(this NetworkReader reader) => reader.ReadBlittable(); + public static Vector2? ReadVector2Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Vector3 ReadVector3(this NetworkReader reader) => reader.ReadBlittable(); + public static Vector3? ReadVector3Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Vector4 ReadVector4(this NetworkReader reader) => reader.ReadBlittable(); + public static Vector4? ReadVector4Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Vector2Int ReadVector2Int(this NetworkReader reader) => reader.ReadBlittable(); + public static Vector2Int? ReadVector2IntNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Vector3Int ReadVector3Int(this NetworkReader reader) => reader.ReadBlittable(); + public static Vector3Int? ReadVector3IntNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Color ReadColor(this NetworkReader reader) => reader.ReadBlittable(); + public static Color? ReadColorNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Color32 ReadColor32(this NetworkReader reader) => reader.ReadBlittable(); + public static Color32? ReadColor32Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Quaternion ReadQuaternion(this NetworkReader reader) => reader.ReadBlittable(); + public static Quaternion? ReadQuaternionNullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + // Rect is a struct with properties instead of fields + public static Rect ReadRect(this NetworkReader reader) => new Rect(reader.ReadVector2(), reader.ReadVector2()); + public static Rect? ReadRectNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRect(reader) : default(Rect?); + + // Plane is a struct with properties instead of fields + public static Plane ReadPlane(this NetworkReader reader) => new Plane(reader.ReadVector3(), reader.ReadFloat()); + public static Plane? ReadPlaneNullable(this NetworkReader reader) => reader.ReadBool() ? ReadPlane(reader) : default(Plane?); + + // Ray is a struct with properties instead of fields + public static Ray ReadRay(this NetworkReader reader) => new Ray(reader.ReadVector3(), reader.ReadVector3()); + public static Ray? ReadRayNullable(this NetworkReader reader) => reader.ReadBool() ? ReadRay(reader) : default(Ray?); + + // LayerMask is a struct with properties instead of fields + public static LayerMask ReadLayerMask(this NetworkReader reader) + { + // LayerMask doesn't have a constructor that takes an initial value. + // 32 layers as a flags enum, max value of 496, we only need a UShort. + LayerMask layerMask = default; + layerMask.value = reader.ReadUShort(); + return layerMask; + } + + public static LayerMask? ReadLayerMaskNullable(this NetworkReader reader) => reader.ReadBool() ? ReadLayerMask(reader) : default(LayerMask?); + + public static Matrix4x4 ReadMatrix4x4(this NetworkReader reader) => reader.ReadBlittable(); + public static Matrix4x4? ReadMatrix4x4Nullable(this NetworkReader reader) => reader.ReadBlittableNullable(); + + public static Guid ReadGuid(this NetworkReader reader) + { +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have Span yet + return new Guid(reader.ReadBytes(16)); +#else + // ReadBlittable(Guid) isn't safe. see ReadBlittable comments. + // Guid is Sequential, but we can't guarantee packing. + if (reader.Remaining >= 16) + { + ReadOnlySpan span = new ReadOnlySpan(reader.buffer.Array, reader.buffer.Offset + reader.Position, 16); + reader.Position += 16; + return new Guid(span); + } + throw new EndOfStreamException($"ReadGuid out of range: {reader}"); +#endif + } + public static Guid? ReadGuidNullable(this NetworkReader reader) => reader.ReadBool() ? ReadGuid(reader) : default(Guid?); + + public static NetworkIdentity ReadNetworkIdentity(this NetworkReader reader) + { + uint netId = reader.ReadUInt(); + if (netId == 0) + return null; + + // NOTE: a netId not being in spawned is common. + // for example, "[SyncVar] NetworkIdentity target" netId would not + // be known on client if the monster walks out of proximity for a + // moment. no need to log any error or warning here. + return Utils.GetSpawnedInServerOrClient(netId); + } + + public static NetworkBehaviour ReadNetworkBehaviour(this NetworkReader reader) + { + // read netId first. + // + // IMPORTANT: if netId != 0, writer always writes componentIndex. + // reusing ReadNetworkIdentity() might return a null NetworkIdentity + // even if netId was != 0 but the identity disappeared on the client, + // resulting in unequal amounts of data being written / read. + // https://github.com/vis2k/Mirror/issues/2972 + uint netId = reader.ReadUInt(); + if (netId == 0) + return null; + + // read component index in any case, BEFORE searching the spawned + // NetworkIdentity by netId. + byte componentIndex = reader.ReadByte(); + + // NOTE: a netId not being in spawned is common. + // for example, "[SyncVar] NetworkIdentity target" netId would not + // be known on client if the monster walks out of proximity for a + // moment. no need to log any error or warning here. + NetworkIdentity identity = Utils.GetSpawnedInServerOrClient(netId); + + return identity != null + ? identity.NetworkBehaviours[componentIndex] + : null; + } + + public static T ReadNetworkBehaviour(this NetworkReader reader) where T : NetworkBehaviour + { + return reader.ReadNetworkBehaviour() as T; + } + + public static NetworkBehaviourSyncVar ReadNetworkBehaviourSyncVar(this NetworkReader reader) + { + uint netId = reader.ReadUInt(); + byte componentIndex = default; + + // if netId is not 0, then index is also sent to read before returning + if (netId != 0) + { + componentIndex = reader.ReadByte(); + } + + return new NetworkBehaviourSyncVar(netId, componentIndex); + } + + public static Transform ReadTransform(this NetworkReader reader) + { + // Don't use null propagation here as it could lead to MissingReferenceException + NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); + return networkIdentity != null ? networkIdentity.transform : null; + } + + public static GameObject ReadGameObject(this NetworkReader reader) + { + // Don't use null propagation here as it could lead to MissingReferenceException + NetworkIdentity networkIdentity = reader.ReadNetworkIdentity(); + return networkIdentity != null ? networkIdentity.gameObject : null; + } + + // while SyncList is recommended for NetworkBehaviours, + // structs may have .List members which weaver needs to be able to + // fully serialize for NetworkMessages etc. + // note that Weaver/Readers/GenerateReader() handles this manually. + public static List ReadList(this NetworkReader reader) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + + // most sizes are small, read size as VarUInt! + uint length = (uint)Compression.DecompressVarUInt(reader); + // uint length = reader.ReadUInt(); + if (length == 0) return null; + length -= 1; + + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (length > NetworkReader.AllocationLimit) + { + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate a List<{typeof(T)}> {length} elements, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); + } + + List result = new List((checked((int)length))); + for (int i = 0; i < length; i++) + { + result.Add(reader.Read()); + } + return result; + } + + // while SyncSet is recommended for NetworkBehaviours, + // structs may have .Set members which weaver needs to be able to + // fully serialize for NetworkMessages etc. + // note that Weaver/Readers/GenerateReader() handles this manually. + public static HashSet ReadHashSet(this NetworkReader reader) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + + // most sizes are small, read size as VarUInt! + uint length = (uint)Compression.DecompressVarUInt(reader); + //uint length = reader.ReadUInt(); + if (length == 0) return null; + length -= 1; + + HashSet result = new HashSet(); + for (int i = 0; i < length; i++) + { + result.Add(reader.Read()); + } + return result; + } + + public static T[] ReadArray(this NetworkReader reader) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + + // most sizes are small, read size as VarUInt! + uint length = (uint)Compression.DecompressVarUInt(reader); + //uint length = reader.ReadUInt(); + if (length == 0) return null; + length -= 1; + + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + if (length > NetworkReader.AllocationLimit) + { + // throw EndOfStream for consistency with ReadBlittable when out of data + throw new EndOfStreamException($"NetworkReader attempted to allocate an Array<{typeof(T)}> with {length} elements, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); + } + + // we can't check if reader.Remaining < length, + // because we don't know sizeof(T) since it's a managed type. + // if (length > reader.Remaining) throw new EndOfStreamException($"Received array that is too large: {length}"); + + T[] result = new T[length]; + for (int i = 0; i < length; i++) + { + result[i] = reader.Read(); + } + return result; + } + + public static Uri ReadUri(this NetworkReader reader) + { + string uriString = reader.ReadString(); + return (string.IsNullOrWhiteSpace(uriString) ? null : new Uri(uriString)); + } + + public static Texture2D ReadTexture2D(this NetworkReader reader) + { + // support 'null' textures for [SyncVar]s etc. + // https://github.com/vis2k/Mirror/issues/3144 + short width = reader.ReadShort(); + if (width == -1) return null; + + // read height + short height = reader.ReadShort(); + + // prevent allocation attacks with a reasonable limit. + // server shouldn't allocate too much on client devices. + // client shouldn't allocate too much on server in ClientToServer [SyncVar]s. + // log an error and return default. + // we don't want attackers to be able to trigger exceptions. + int totalSize = width * height; + if (totalSize > NetworkReader.AllocationLimit) + { + Debug.LogWarning($"NetworkReader attempted to allocate a Texture2D with total size (width * height) of {totalSize}, which is larger than the allowed limit of {NetworkReader.AllocationLimit}."); + return null; + } + + Texture2D texture2D = new Texture2D(width, height); + + // read pixel content + Color32[] pixels = reader.ReadArray(); + texture2D.SetPixels32(pixels); + texture2D.Apply(); + return texture2D; + } + + public static Sprite ReadSprite(this NetworkReader reader) + { + // support 'null' textures for [SyncVar]s etc. + // https://github.com/vis2k/Mirror/issues/3144 + Texture2D texture = reader.ReadTexture2D(); + if (texture == null) return null; + + // otherwise create a valid sprite + return Sprite.Create(texture, reader.ReadRect(), reader.ReadVector2()); + } + + public static DateTime ReadDateTime(this NetworkReader reader) => DateTime.FromOADate(reader.ReadDouble()); + public static DateTime? ReadDateTimeNullable(this NetworkReader reader) => reader.ReadBool() ? ReadDateTime(reader) : default(DateTime?); + } +} diff --git a/Assets/Mirror/Core/NetworkReaderExtensions.cs.meta b/Assets/Mirror/Core/NetworkReaderExtensions.cs.meta new file mode 100644 index 0000000..97f24e5 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderExtensions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 364a9f7ccd5541e19aa2ae0b81f0b3cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkReaderExtensions.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkReaderPool.cs b/Assets/Mirror/Core/NetworkReaderPool.cs new file mode 100644 index 0000000..f44adb8 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderPool.cs @@ -0,0 +1,48 @@ +// API consistent with Microsoft's ObjectPool. +using System; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + /// Pool of NetworkReaders to avoid allocations. + public static class NetworkReaderPool + { + // reuse Pool + // we still wrap it in NetworkReaderPool.Get/Recyle so we can reset the + // position and array before reusing. + static readonly Pool Pool = new Pool( + // byte[] will be assigned in GetReader + () => new NetworkReaderPooled(new byte[]{}), + // initial capacity to avoid allocations in the first few frames + 1000 + ); + + // expose count for testing + public static int Count => Pool.Count; + + /// Get the next reader in the pool. If pool is empty, creates a new Reader + public static NetworkReaderPooled Get(byte[] bytes) + { + // grab from pool & set buffer + NetworkReaderPooled reader = Pool.Get(); + reader.SetBuffer(bytes); + return reader; + } + + /// Get the next reader in the pool. If pool is empty, creates a new Reader + public static NetworkReaderPooled Get(ArraySegment segment) + { + // grab from pool & set buffer + NetworkReaderPooled reader = Pool.Get(); + reader.SetBuffer(segment); + return reader; + } + + /// Returns a reader to the pool. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Return(NetworkReaderPooled reader) + { + Pool.Return(reader); + } + } +} diff --git a/Assets/Mirror/Core/NetworkReaderPool.cs.meta b/Assets/Mirror/Core/NetworkReaderPool.cs.meta new file mode 100644 index 0000000..60bf9f6 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2bacff63613ad634a98f9e4d15d29dbf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkReaderPool.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkReaderPooled.cs b/Assets/Mirror/Core/NetworkReaderPooled.cs new file mode 100644 index 0000000..1508701 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderPooled.cs @@ -0,0 +1,12 @@ +using System; + +namespace Mirror +{ + /// Pooled NetworkReader, automatically returned to pool when using 'using' + public sealed class NetworkReaderPooled : NetworkReader, IDisposable + { + internal NetworkReaderPooled(byte[] bytes) : base(bytes) {} + internal NetworkReaderPooled(ArraySegment segment) : base(segment) {} + public void Dispose() => NetworkReaderPool.Return(this); + } +} diff --git a/Assets/Mirror/Core/NetworkReaderPooled.cs.meta b/Assets/Mirror/Core/NetworkReaderPooled.cs.meta new file mode 100644 index 0000000..0f7dee9 --- /dev/null +++ b/Assets/Mirror/Core/NetworkReaderPooled.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: faafa97c32e44adf8e8888de817a370a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkReaderPooled.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs new file mode 100644 index 0000000..5df6b9c --- /dev/null +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -0,0 +1,2111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mirror.RemoteCalls; +using UnityEngine; + +namespace Mirror +{ + public enum ReplacePlayerOptions + { + /// Player Object remains active on server and clients. Ownership is not removed + KeepAuthority, + /// Player Object remains active on server and clients. Only ownership is removed + KeepActive, + /// Player Object is unspawned on clients but remains on server + Unspawn, + /// Player Object is destroyed on server and clients + Destroy + } + + public enum RemovePlayerOptions + { + /// Player Object remains active on server and clients. Only ownership is removed + KeepActive, + /// Player Object is unspawned on clients but remains on server + Unspawn, + /// Player Object is destroyed on server and clients + Destroy + } + + /// NetworkServer handles remote connections and has a local connection for a local client. + public static partial class NetworkServer + { + static bool initialized; + public static int maxConnections; + + /// Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE. + // overwritten by NetworkManager (if any) + public static int tickRate = 60; + + // tick rate is in Hz. + // convert to interval in seconds for convenience where needed. + // + // send interval is 1 / sendRate. + // but for tests we need a way to set it to exactly 0. + // 1 / int.max would not be exactly 0, so handel that manually. + public static float tickInterval => tickRate < int.MaxValue ? 1f / tickRate : 0; // for 30 Hz, that's 33ms + + // time & value snapshot interpolation are separate. + // -> time is interpolated globally on NetworkClient / NetworkConnection + // -> value is interpolated per-component, i.e. NetworkTransform. + // however, both need to be on the same send interval. + public static int sendRate => tickRate; + public static float sendInterval => sendRate < int.MaxValue ? 1f / sendRate : 0; // for 30 Hz, that's 33ms + static double lastSendTime; + + /// Connection to host mode client (if any) + public static LocalConnectionToClient localConnection { get; private set; } + + /// Dictionary of all server connections, with connectionId as key + public static Dictionary connections = + new Dictionary(); + + /// Message Handlers dictionary, with messageId as key + internal static Dictionary handlers = + new Dictionary(); + + /// All spawned NetworkIdentities by netId. + // server sees ALL spawned ones. + public static readonly Dictionary spawned = + new Dictionary(); + + /// Single player mode can set listen=false to not accept incoming connections. + public static bool listen; + + // DEPRECATED 2024-10-14 + [Obsolete("NetworkServer.dontListen was replaced with NetworkServer.listen. The new value is the opposite, and avoids double negatives like 'dontListen=false'")] + public static bool dontListen + { + get => !listen; + set => listen = !value; + } + + /// active checks if the server has been started either has standalone or as host server. + public static bool active { get; internal set; } + + /// active checks if the server has been started in host mode. + // naming consistent with NetworkClient.activeHost. + public static bool activeHost => localConnection != null; + + // scene loading + public static bool isLoadingScene; + + // interest management component (optional) + // by default, everyone observes everyone + public static InterestManagementBase aoi; + + // For security, it is recommended to disconnect a player if a networked + // action triggers an exception\nThis could prevent components being + // accessed in an undefined state, which may be an attack vector for + // exploits. + // + // However, some games may want to allow exceptions in order to not + // interrupt the player's experience. + public static bool exceptionsDisconnect = true; // security by default + + // Mirror global disconnect inactive option, independent of Transport. + // not all Transports do this properly, and it's easiest to configure this just once. + // this is very useful for some projects, keep it. + public static bool disconnectInactiveConnections; + public static float disconnectInactiveTimeout = 60; + + // OnConnected / OnDisconnected used to be NetworkMessages that were + // invoked. this introduced a bug where external clients could send + // Connected/Disconnected messages over the network causing undefined + // behaviour. + // => public so that custom NetworkManagers can hook into it + public static Action OnConnectedEvent; + public static Action OnDisconnectedEvent; + public static Action OnErrorEvent; + public static Action OnTransportExceptionEvent; + + // keep track of actual achieved tick rate. + // might become lower under heavy load. + // very useful for profiling etc. + // measured over 1s each, same as frame rate. no EMA here. + public static int actualTickRate; + static double actualTickRateStart; // start time when counting + static int actualTickRateCounter; // current counter since start + + // profiling + // includes transport update time, because transport calls handlers etc. + // averaged over 1s by passing 'tickRate' to constructor. + public static TimeSample earlyUpdateDuration; + public static TimeSample lateUpdateDuration; + + // capture full Unity update time from before Early- to after LateUpdate + public static TimeSample fullUpdateDuration; + + /// Starts server and listens to incoming connections with max connections limit. + public static void Listen(int maxConns) + { + Initialize(); + maxConnections = maxConns; + + // only start server if we want to listen + if (listen) + { + Transport.active.ServerStart(); + + if (Transport.active is PortTransport portTransport) + { + if (Utils.IsHeadless()) + { +#if !UNITY_EDITOR + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Server listening on port {portTransport.Port}"); + Console.ResetColor(); +#else + Debug.Log($"Server listening on port {portTransport.Port}"); +#endif + } + } + else + Debug.Log("Server started listening"); + } + + active = true; + RegisterMessageHandlers(); + } + + // initialization / shutdown /////////////////////////////////////////// + static void Initialize() + { + if (initialized) + return; + + // safety: ensure Weaving succeded. + // if it silently failed, we would get lots of 'writer not found' + // and other random errors at runtime instead. this is cleaner. + if (!WeaverFuse.Weaved()) + { + // if it failed, throw an exception to early exit all Listen calls. + throw new Exception("NetworkServer won't start because Weaving failed or didn't run."); + } + + // Debug.Log($"NetworkServer Created version {Version.Current}"); + + //Make sure connections are cleared in case any old connections references exist from previous sessions + connections.Clear(); + + // reset Interest Management so that rebuild intervals + // start at 0 when starting again. + if (aoi != null) aoi.ResetState(); + + // reset NetworkTime + NetworkTime.ResetStatics(); + + Debug.Assert(Transport.active != null, "There was no active transport when calling NetworkServer.Listen, If you are calling Listen manually then make sure to set 'Transport.active' first"); + AddTransportHandlers(); + + initialized = true; + + // profiling + earlyUpdateDuration = new TimeSample(sendRate); + lateUpdateDuration = new TimeSample(sendRate); + fullUpdateDuration = new TimeSample(sendRate); + } + + static void AddTransportHandlers() + { + // += so that other systems can also hook into it (i.e. statistics) +#pragma warning disable CS0618 // Type or member is obsolete + Transport.active.OnServerConnected += OnTransportConnected; +#pragma warning restore CS0618 // Type or member is obsolete + Transport.active.OnServerConnectedWithAddress += OnTransportConnectedWithAddress; + Transport.active.OnServerDataReceived += OnTransportData; + Transport.active.OnServerDisconnected += OnTransportDisconnected; + Transport.active.OnServerError += OnTransportError; + Transport.active.OnServerTransportException += OnTransportException; + } + + /// Shuts down the server and disconnects all clients + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + public static void Shutdown() + { + if (initialized) + { + DisconnectAll(); + + // stop the server. + // we do NOT call Transport.Shutdown, because someone only + // called NetworkServer.Shutdown. we can't assume that the + // client is supposed to be shut down too! + // + // NOTE: stop no matter what, even if 'dontListen': + // someone might enabled dontListen at runtime. + // but we still need to stop the server. + // fixes https://github.com/vis2k/Mirror/issues/2536 + Transport.active.ServerStop(); + + // transport handlers are hooked into when initializing. + // so only remove them when shutting down. + RemoveTransportHandlers(); + + initialized = false; + } + + // Reset all statics here.... + listen = true; + isLoadingScene = false; + lastSendTime = 0; + actualTickRate = 0; + + localConnection = null; + + connections.Clear(); + connectionsCopy.Clear(); + handlers.Clear(); + + // destroy all spawned objects, _then_ set inactive. + // make sure .active is still true before calling this. + // otherwise modifying SyncLists in OnStopServer would throw + // because .IsWritable() check checks if NetworkServer.active. + // https://github.com/MirrorNetworking/Mirror/issues/3344 + CleanupSpawned(); + active = false; + + // sets nextNetworkId to 1 + // sets clientAuthorityCallback to null + // sets previousLocalPlayer to null + NetworkIdentity.ResetStatics(); + + // clear events. someone might have hooked into them before, but + // we don't want to use those hooks after Shutdown anymore. + OnConnectedEvent = null; + OnDisconnectedEvent = null; + OnErrorEvent = null; + OnTransportExceptionEvent = null; + + if (aoi != null) aoi.ResetState(); + } + + static void RemoveTransportHandlers() + { + // -= so that other systems can also hook into it (i.e. statistics) +#pragma warning disable CS0618 // Type or member is obsolete + Transport.active.OnServerConnected -= OnTransportConnected; +#pragma warning restore CS0618 // Type or member is obsolete + Transport.active.OnServerConnectedWithAddress -= OnTransportConnectedWithAddress; + Transport.active.OnServerDataReceived -= OnTransportData; + Transport.active.OnServerDisconnected -= OnTransportDisconnected; + Transport.active.OnServerError -= OnTransportError; + } + + // Note: NetworkClient.DestroyAllClientObjects does the same on client. + static void CleanupSpawned() + { + // iterate a COPY of spawned. + // DestroyObject removes them from the original collection. + // removing while iterating is not allowed. + foreach (NetworkIdentity identity in spawned.Values.ToList()) + { + if (identity != null) + { + // NetworkServer.Destroy resets if scene object, destroys if prefab. + Destroy(identity.gameObject); + } + } + + spawned.Clear(); + } + + internal static void RegisterMessageHandlers() + { + RegisterHandler(OnClientReadyMessage); + RegisterHandler(OnCommandMessage); + RegisterHandler(NetworkTime.OnServerPing, false); + RegisterHandler(NetworkTime.OnServerPong, false); + RegisterHandler(OnEntityStateMessage, true); + RegisterHandler(OnTimeSnapshotMessage, false); // unreliable may arrive before reliable authority went through + } + + // remote calls //////////////////////////////////////////////////////// + // Handle command from specific player, this could be one of multiple + // players on a single client + // default ready handler. + static void OnClientReadyMessage(NetworkConnectionToClient conn, ReadyMessage msg) + { + // Debug.Log($"Default handler for ready message from {conn}"); + SetClientReady(conn); + } + + static void OnCommandMessage(NetworkConnectionToClient conn, CommandMessage msg, int channelId) + { + if (!conn.isReady) + { + // Clients may be set NotReady due to scene change or other game logic by user, e.g. respawning. + // Ignore commands that may have been in flight before client received NotReadyMessage message. + // Unreliable messages may be out of order, so don't spam warnings for those. + if (channelId == Channels.Reliable) + { + // Attempt to identify the target object, component, and method to narrow down the cause of the error. + if (spawned.TryGetValue(msg.netId, out NetworkIdentity netIdentity)) + if (msg.componentIndex < netIdentity.NetworkBehaviours.Length && netIdentity.NetworkBehaviours[msg.componentIndex] is NetworkBehaviour component) + if (RemoteProcedureCalls.GetFunctionMethodName(msg.functionHash, out string methodName)) + { + Debug.LogWarning($"Command {methodName} received for {netIdentity.name} [netId={msg.netId}] component {component.name} [index={msg.componentIndex}] when client not ready.\nThis may be ignored if client intentionally set NotReady."); + return; + } + + if (RemoteProcedureCalls.GetFunctionMethodName(msg.functionHash, out string method)) + { + Debug.LogWarning($"Command {method} received from {conn} when client was not ready.\nThis may be ignored if client intentionally set NotReady."); + return; + } + + Debug.LogWarning($"Command received from {conn} while client is not ready.\nThis may be ignored if client intentionally set NotReady."); + } + return; + } + + if (!spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) + { + // over reliable channel, commands should always come after spawn. + // over unreliable, they might come in before the object was spawned. + // for example, NetworkTransform. + // let's not spam the console for unreliable out of order messages. + if (channelId == Channels.Reliable) + Debug.LogWarning($"Spawned object not found when handling Command message netId={msg.netId}"); + return; + } + + // Commands can be for player objects, OR other objects with client-authority + // -> so if this connection's controller has a different netId then + // only allow the command if clientAuthorityOwner + bool requiresAuthority = RemoteProcedureCalls.CommandRequiresAuthority(msg.functionHash); + if (requiresAuthority && identity.connectionToClient != conn) + { + // Attempt to identify the component and method to narrow down the cause of the error. + if (msg.componentIndex < identity.NetworkBehaviours.Length && identity.NetworkBehaviours[msg.componentIndex] is NetworkBehaviour component) + if (RemoteProcedureCalls.GetFunctionMethodName(msg.functionHash, out string methodName)) + { + Debug.LogWarning($"Command {methodName} received for {identity.name} [netId={msg.netId}] component {component.name} [index={msg.componentIndex}] without authority"); + return; + } + + Debug.LogWarning($"Command received for {identity.name} [netId={msg.netId}] without authority"); + return; + } + + // Debug.Log($"OnCommandMessage for netId:{msg.netId} conn:{conn}"); + + using (NetworkReaderPooled networkReader = NetworkReaderPool.Get(msg.payload)) + identity.HandleRemoteCall(msg.componentIndex, msg.functionHash, RemoteCallType.Command, networkReader, conn); + } + + // client to server broadcast ////////////////////////////////////////// + // for client's owned ClientToServer components. + static void OnEntityStateMessage(NetworkConnectionToClient connection, EntityStateMessage message) + { + // need to validate permissions carefully. + // an attacker may attempt to modify a not-owned or not-ClientToServer component. + + // valid netId? + if (spawned.TryGetValue(message.netId, out NetworkIdentity identity) && identity != null) + { + // owned by the connection? + if (identity.connectionToClient == connection) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message.payload)) + { + // DeserializeServer checks permissions internally. + // failure to deserialize disconnects to prevent exploits. + if (!identity.DeserializeServer(reader)) + { + if (exceptionsDisconnect) + { + Debug.LogError($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}, Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"Server failed to deserialize client state for {identity.name} with netId={identity.netId}."); + } + } + } + // An attacker may attempt to modify another connection's entity + // This could also be a race condition of message in flight when + // RemoveClientAuthority is called, so not malicious. + // Don't disconnect, just log the warning. + else + Debug.LogWarning($"EntityStateMessage from {connection} for {identity.name} without authority."); + } + // no warning. don't spam server logs. + // else Debug.LogWarning($"Did not find target for sync message for {message.netId} . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message."); + } + + // client sends TimeSnapshotMessage every sendInterval. + // batching already includes the remoteTimestamp. + // we simply insert it on-message here. + // => only for reliable channel. unreliable would always arrive earlier. + static void OnTimeSnapshotMessage(NetworkConnectionToClient connection, TimeSnapshotMessage _) + { + // insert another snapshot for snapshot interpolation. + // before calling OnDeserialize so components can use + // NetworkTime.time and NetworkTime.timeStamp. + + // TODO validation? + // maybe we shouldn't allow timeline to deviate more than a certain %. + // for now, this is only used for client authority movement. + + // Unity 2019 doesn't have Time.timeAsDouble yet + // + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 + connection.OnTimeSnapshot(new TimeSnapshot(connection.remoteTimeStamp, NetworkTime.localTime)); + } + + // connections ///////////////////////////////////////////////////////// + /// Add a connection and setup callbacks. Returns true if not added yet. + public static bool AddConnection(NetworkConnectionToClient conn) + { + if (!connections.ContainsKey(conn.connectionId)) + { + // connection cannot be null here or conn.connectionId + // would throw NRE + connections[conn.connectionId] = conn; + return true; + } + // already a connection with this id + return false; + } + + /// Removes a connection by connectionId. Returns true if removed. + public static bool RemoveConnection(int connectionId) => + connections.Remove(connectionId); + + // called by LocalClient to add itself. don't call directly. + // TODO consider internal setter instead? + internal static void SetLocalConnection(LocalConnectionToClient conn) + { + if (localConnection != null) + { + Debug.LogError("Local Connection already exists"); + return; + } + + localConnection = conn; + } + + // removes local connection to client + internal static void RemoveLocalConnection() + { + if (localConnection != null) + { + localConnection.Disconnect(); + localConnection = null; + } + RemoveConnection(0); + } + + /// True if we have external connections (that are not host) + public static bool HasExternalConnections() + { + // any connections? + if (connections.Count > 0) + { + // only host connection? + if (connections.Count == 1 && localConnection != null) + return false; + + // otherwise we have real external connections + return true; + } + return false; + } + + // send //////////////////////////////////////////////////////////////// + /// Send a message to all clients, even those that haven't joined the world yet (non ready) + public static void SendToAll(T message, int channelId = Channels.Reliable, bool sendToReadyOnly = false) + where T : struct, NetworkMessage + { + if (!active) + { + Debug.LogWarning("Can not send using NetworkServer.SendToAll(T msg) because NetworkServer is not active"); + return; + } + + // Debug.Log($"Server.SendToAll {typeof(T)}"); + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // pack message only once + NetworkMessages.Pack(message, writer); + ArraySegment segment = writer.ToArraySegment(); + + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToAll: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + + // filter and then send to all internet connections at once + // -> makes code more complicated, but is HIGHLY worth it to + // avoid allocations, allow for multicast, etc. + int count = 0; + foreach (NetworkConnectionToClient conn in connections.Values) + { + if (sendToReadyOnly && !conn.isReady) + continue; + + count++; + conn.Send(segment, channelId); + } + + NetworkDiagnostics.OnSend(message, channelId, segment.Count, count); + } + } + + /// Send a message to all clients which have joined the world (are ready). + // TODO put rpcs into NetworkServer.Update WorldState packet, then finally remove SendToReady! + public static void SendToReady(T message, int channelId = Channels.Reliable) + where T : struct, NetworkMessage + { + if (!active) + { + Debug.LogWarning("Can not send using NetworkServer.SendToReady(T msg) because NetworkServer is not active"); + return; + } + + SendToAll(message, channelId, true); + } + + // this is like SendToReadyObservers - but it doesn't check the ready flag on the connection. + // this is used for ObjectDestroy messages. + static void SendToObservers(NetworkIdentity identity, T message, int channelId = Channels.Reliable) + where T : struct, NetworkMessage + { + // Debug.Log($"Server.SendToObservers {typeof(T)}"); + if (identity == null || identity.observers.Count == 0) + return; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // pack message into byte[] once + NetworkMessages.Pack(message, writer); + ArraySegment segment = writer.ToArraySegment(); + + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToObservers: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + + foreach (NetworkConnectionToClient conn in identity.observers.Values) + { + conn.Send(segment, channelId); + } + + NetworkDiagnostics.OnSend(message, channelId, segment.Count, identity.observers.Count); + } + } + + /// Send a message to only clients which are ready with option to include the owner of the object identity + // TODO obsolete this later. it's not used anymore + public static void SendToReadyObservers(NetworkIdentity identity, T message, bool includeOwner = true, int channelId = Channels.Reliable) + where T : struct, NetworkMessage + { + // Debug.Log($"Server.SendToReady {typeof(T)}"); + if (identity == null || identity.observers.Count == 0) + return; + + using (NetworkWriterPooled writer = NetworkWriterPool.Get()) + { + // pack message only once + NetworkMessages.Pack(message, writer); + ArraySegment segment = writer.ToArraySegment(); + + // validate packet size immediately. + // we know how much can fit into one batch at max. + // if it's larger, log an error immediately with the type . + // previously we only logged in Update() when processing batches, + // but there we don't have type information anymore. + int max = NetworkMessages.MaxMessageSize(channelId); + if (writer.Position > max) + { + Debug.LogError($"NetworkServer.SendToReadyObservers: message of type {typeof(T)} with a size of {writer.Position} bytes is larger than the max allowed message size in one batch: {max}.\nThe message was dropped, please make it smaller."); + return; + } + + int count = 0; + foreach (NetworkConnectionToClient conn in identity.observers.Values) + { + bool isOwner = conn == identity.connectionToClient; + if ((!isOwner || includeOwner) && conn.isReady) + { + count++; + conn.Send(segment, channelId); + } + } + + NetworkDiagnostics.OnSend(message, channelId, segment.Count, count); + } + } + + /// Send a message to only clients which are ready including the owner of the NetworkIdentity + // TODO obsolete this later. it's not used anymore + public static void SendToReadyObservers(NetworkIdentity identity, T message, int channelId) + where T : struct, NetworkMessage + { + SendToReadyObservers(identity, message, true, channelId); + } + + // transport events //////////////////////////////////////////////////// + // called by transport + static void OnTransportConnected(int connectionId) + => OnTransportConnectedWithAddress(connectionId, Transport.active.ServerGetClientAddress(connectionId)); + + static void OnTransportConnectedWithAddress(int connectionId, string clientAddress) + { + if (IsConnectionAllowed(connectionId, clientAddress)) + { + // create a connection + NetworkConnectionToClient conn = new NetworkConnectionToClient(connectionId, clientAddress); + OnConnected(conn); + } + else + { + // kick the client immediately + Transport.active.ServerDisconnect(connectionId); + } + } + + static bool IsConnectionAllowed(int connectionId, string address) + { + // only accept connections while listening + if (!listen) + { + Debug.Log($"Server not listening, rejecting connectionId={connectionId} with address={address}"); + return false; + } + + // connectionId needs to be != 0 because 0 is reserved for local player + // note that some transports like kcp generate connectionId by + // hashing which can be < 0 as well, so we need to allow < 0! + if (connectionId == 0) + { + Debug.LogError($"Server.HandleConnect: invalid connectionId={connectionId}. Needs to be != 0, because 0 is reserved for local player."); + return false; + } + + // connectionId not in use yet? + if (connections.ContainsKey(connectionId)) + { + Debug.LogError($"Server connectionId={connectionId} already in use. Client with address={address} will be kicked"); + return false; + } + + // are more connections allowed? if not, kick + // (it's easier to handle this in Mirror, so Transports can have + // less code and third party transport might not do that anyway) + // (this way we could also send a custom 'tooFull' message later, + // Transport can't do that) + if (connections.Count >= maxConnections) + { + Debug.LogError($"Server full, client connectionId={connectionId} with address={address} will be kicked"); + return false; + } + + return true; + } + + internal static void OnConnected(NetworkConnectionToClient conn) + { + // Debug.Log($"Server accepted client:{conn}"); + + // add connection and invoke connected event + AddConnection(conn); + OnConnectedEvent?.Invoke(conn); + } + + static bool UnpackAndInvoke(NetworkConnectionToClient connection, NetworkReader reader, int channelId) + { + if (NetworkMessages.UnpackId(reader, out ushort msgType)) + { + // try to invoke the handler for that message + if (handlers.TryGetValue(msgType, out NetworkMessageDelegate handler)) + { + handler.Invoke(connection, reader, channelId); + connection.lastMessageTime = Time.time; + return true; + } + else + { + // message in a batch are NOT length prefixed to save bandwidth. + // every message needs to be handled and read until the end. + // otherwise it would overlap into the next message. + // => need to warn and disconnect to avoid undefined behaviour. + // => WARNING, not error. can happen if attacker sends random data. + Debug.LogWarning($"Unknown message id: {msgType} for connection: {connection}. This can happen if no handler was registered for this message."); + // simply return false. caller is responsible for disconnecting. + //connection.Disconnect(); + return false; + } + } + else + { + // => WARNING, not error. can happen if attacker sends random data. + Debug.LogWarning($"Invalid message header for connection: {connection}."); + // simply return false. caller is responsible for disconnecting. + //connection.Disconnect(); + return false; + } + } + + // called by transport + internal static void OnTransportData(int connectionId, ArraySegment data, int channelId) + { + if (connections.TryGetValue(connectionId, out NetworkConnectionToClient connection)) + { + // client might batch multiple messages into one packet. + // feed it to the Unbatcher. + // NOTE: we don't need to associate a channelId because we + // always process all messages in the batch. + if (!connection.unbatcher.AddBatch(data)) + { + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id)."); + + return; + } + + // process all messages in the batch. + // only while NOT loading a scene. + // if we get a scene change message, then we need to stop + // processing. otherwise we might apply them to the old scene. + // => fixes https://github.com/vis2k/Mirror/issues/2651 + // + // NOTE: if scene starts loading, then the rest of the batch + // would only be processed when OnTransportData is called + // the next time. + // => consider moving processing to NetworkEarlyUpdate. + while (!isLoadingScene && + connection.unbatcher.GetNextMessage(out ArraySegment message, out double remoteTimestamp)) + { + using (NetworkReaderPooled reader = NetworkReaderPool.Get(message)) + { + // enough to read at least header size? + if (reader.Remaining >= NetworkMessages.IdSize) + { + // make remoteTimeStamp available to the user + connection.remoteTimeStamp = remoteTimestamp; + + // handle message + if (!UnpackAndInvoke(connection, reader, channelId)) + { + // warn, disconnect and return if failed + // -> warning because attackers might send random data + // -> messages in a batch aren't length prefixed. + // failing to read one would cause undefined + // behaviour for every message afterwards. + // so we need to disconnect. + // -> return to avoid the below unbatches.count error. + // we already disconnected and handled it. + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: failed to unpack and invoke message. Disconnecting {connectionId}."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: failed to unpack and invoke message from connectionId:{connectionId}."); + + return; + } + } + // otherwise disconnect + else + { + if (exceptionsDisconnect) + { + Debug.LogError($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id). Disconnecting."); + connection.Disconnect(); + } + else + Debug.LogWarning($"NetworkServer: received message from connectionId:{connectionId} was too short (messages should start with message id)."); + + return; + } + } + } + + // if we weren't interrupted by a scene change, + // then all batched messages should have been processed now. + // otherwise batches would silently grow. + // we need to log an error to avoid debugging hell. + // + // EXAMPLE: https://github.com/vis2k/Mirror/issues/2882 + // -> UnpackAndInvoke silently returned because no handler for id + // -> Reader would never be read past the end + // -> Batch would never be retired because end is never reached + // + // NOTE: prefixing every message in a batch with a length would + // avoid ever not reading to the end. for extra bandwidth. + // + // IMPORTANT: always keep this check to detect memory leaks. + // this took half a day to debug last time. + if (!isLoadingScene && connection.unbatcher.BatchesCount > 0) + { + Debug.LogError($"Still had {connection.unbatcher.BatchesCount} batches remaining after processing, even though processing was not interrupted by a scene change. This should never happen, as it would cause ever growing batches.\nPossible reasons:\n* A message didn't deserialize as much as it serialized\n*There was no message handler for a message id, so the reader wasn't read until the end."); + } + } + else Debug.LogError($"HandleData Unknown connectionId:{connectionId}"); + } + + // called by transport + // IMPORTANT: often times when disconnecting, we call this from Mirror + // too because we want to remove the connection and handle + // the disconnect immediately. + // => which is fine as long as we guarantee it only runs once + // => which we do by removing the connection! + internal static void OnTransportDisconnected(int connectionId) + { + // Debug.Log($"Server disconnect client:{connectionId}"); + if (connections.TryGetValue(connectionId, out NetworkConnectionToClient conn)) + { + conn.Cleanup(); + RemoveConnection(connectionId); + // Debug.Log($"Server lost client:{connectionId}"); + + // NetworkManager hooks into OnDisconnectedEvent to make + // DestroyPlayerForConnection(conn) optional, e.g. for PvP MMOs + // where players shouldn't be able to escape combat instantly. + if (OnDisconnectedEvent != null) + { + OnDisconnectedEvent.Invoke(conn); + } + // if nobody hooked into it, then simply call DestroyPlayerForConnection + else + { + DestroyPlayerForConnection(conn); + } + } + } + + // transport errors are forwarded to high level + static void OnTransportError(int connectionId, TransportError error, string reason) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Server Transport Error for connId={connectionId}: {error}: {reason}. This is fine."); + // try get connection. passes null otherwise. + connections.TryGetValue(connectionId, out NetworkConnectionToClient conn); + OnErrorEvent?.Invoke(conn, error, reason); + } + + // transport errors are forwarded to high level + static void OnTransportException(int connectionId, Exception exception) + { + // transport errors will happen. logging a warning is enough. + // make sure the user does not panic. + Debug.LogWarning($"Server Transport Exception for connId={connectionId}: {exception}"); + // try get connection. passes null otherwise. + connections.TryGetValue(connectionId, out NetworkConnectionToClient conn); + OnTransportExceptionEvent?.Invoke(conn, exception); + } + + /// Destroys all of the connection's owned objects on the server. + // This is used when a client disconnects, to remove the players for + // that client. This also destroys non-player objects that have client + // authority set for this connection. + public static void DestroyPlayerForConnection(NetworkConnectionToClient conn) + { + // destroy all objects owned by this connection, including the player object + conn.DestroyOwnedObjects(); + // remove connection from all of its observing entities observers + // fixes https://github.com/vis2k/Mirror/issues/2737 + // -> cleaning those up in NetworkConnection.Disconnect is NOT enough + // because voluntary disconnects from the other end don't call + // NetworkConnection.Disconnect() + conn.RemoveFromObservingsObservers(); + conn.identity = null; + } + + // message handlers //////////////////////////////////////////////////// + /// Register a handler for message type T. Most should require authentication. + // TODO obsolete this some day to always use the channelId version. + // all handlers in this version are wrapped with 1 extra action. + public static void RegisterHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + if (handlers.ContainsKey(msgType)) + { + Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); + } + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); + } + + /// Register a handler for message type T. Most should require authentication. + // This version passes channelId to the handler. + public static void RegisterHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + if (handlers.ContainsKey(msgType)) + { + Debug.LogWarning($"NetworkServer.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning."); + } + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for message type T. Most should require authentication. + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ReplaceHandler((_, value) => { handler(value); }, requireAuthentication); + } + + /// Replace a handler for message type T. Most should require authentication. + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); + } + + /// Replace a handler for message type T. Most should require authentication. + public static void ReplaceHandler(Action handler, bool requireAuthentication = true) + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + + // register Id <> Type in lookup for debugging. + NetworkMessages.Lookup[msgType] = typeof(T); + + handlers[msgType] = NetworkMessages.WrapHandler(handler, requireAuthentication, exceptionsDisconnect); + } + + /// Unregister a handler for a message type T. + public static void UnregisterHandler() + where T : struct, NetworkMessage + { + ushort msgType = NetworkMessageId.Id; + handlers.Remove(msgType); + } + + /// Clears all registered message handlers. + public static void ClearHandlers() => handlers.Clear(); + + internal static bool GetNetworkIdentity(GameObject go, out NetworkIdentity identity) + { + if (!go.TryGetComponent(out identity)) + { + Debug.LogError($"GameObject {go.name} doesn't have NetworkIdentity."); + return false; + } + return true; + } + + // disconnect ////////////////////////////////////////////////////////// + /// Disconnect all connections, including the local connection. + // synchronous: handles disconnect events and cleans up fully before returning! + public static void DisconnectAll() + { + // disconnect and remove all connections. + // we can not use foreach here because if + // conn.Disconnect -> Transport.ServerDisconnect calls + // OnDisconnect -> NetworkServer.OnDisconnect(connectionId) + // immediately then OnDisconnect would remove the connection while + // we are iterating here. + // see also: https://github.com/vis2k/Mirror/issues/2357 + // this whole process should be simplified some day. + // until then, let's copy .Values to avoid InvalidOperationException. + // note that this is only called when stopping the server, so the + // copy is no performance problem. + foreach (NetworkConnectionToClient conn in connections.Values.ToList()) + { + // disconnect via connection->transport + conn.Disconnect(); + + // we want this function to be synchronous: handle disconnect + // events and clean up fully before returning. + // -> OnTransportDisconnected can safely be called without + // waiting for the Transport's callback. + // -> it has checks to only run once. + + // call OnDisconnected unless local player in host mod + // TODO unnecessary check? + if (conn.connectionId != NetworkConnection.LocalConnectionId) + OnTransportDisconnected(conn.connectionId); + } + + // cleanup + connections.Clear(); + localConnection = null; + // this used to set active=false. + // however, then Shutdown can't properly destroy objects: + // https://github.com/MirrorNetworking/Mirror/issues/3344 + // "DisconnectAll" should only disconnect all, not set inactive. + // active = false; + } + + // add/remove/replace player /////////////////////////////////////////// + /// Called by server after AddPlayer message to add the player for the connection. + // When a player is added for a connection, the client for that + // connection is made ready automatically. The player object is + // automatically spawned, so you do not need to call NetworkServer.Spawn + // for that object. This function is used for "adding" a player, not for + // "replacing" the player on a connection. If there is already a player + // on this playerControllerId for this connection, this will fail. + public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId) + { + if (GetNetworkIdentity(player, out NetworkIdentity identity)) + { + identity.assetId = assetId; + } + return AddPlayerForConnection(conn, player); + } + + /// Called by server after AddPlayer message to add the player for the connection. + // When a player is added for a connection, the client for that + // connection is made ready automatically. The player object is + // automatically spawned, so you do not need to call NetworkServer.Spawn + // for that object. This function is used for "adding" a player, not for + // "replacing" the player on a connection. If there is already a player + // on this playerControllerId for this connection, this will fail. + public static bool AddPlayerForConnection(NetworkConnectionToClient conn, GameObject player) + { + if (!player.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogWarning($"AddPlayer: player GameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); + return false; + } + + // cannot have a player object in "Add" version + if (conn.identity != null) + { + Debug.Log("AddPlayer: player object already exists"); + return false; + } + + // make sure we have a controller before we call SetClientReady + // because the observers will be rebuilt only if we have a controller + conn.identity = identity; + + // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients) + identity.SetClientOwner(conn); + + // special case, we are in host mode, set hasAuthority to true so that all overrides see it + if (conn is LocalConnectionToClient) + { + identity.isOwned = true; + NetworkClient.InternalAddPlayer(identity); + } + + // set ready if not set yet + SetClientReady(conn); + + // Debug.Log($"Adding new playerGameObject object netId: {identity.netId} asset ID: {identity.assetId}"); + + Respawn(identity); + return true; + } + + // Deprecated 2024-008-09 + [Obsolete("Use ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId, ReplacePlayerOptions replacePlayerOptions) instead")] + public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId, bool keepAuthority = false) + { + if (GetNetworkIdentity(player, out NetworkIdentity identity)) + identity.assetId = assetId; + + return ReplacePlayerForConnection(conn, player, keepAuthority ? ReplacePlayerOptions.KeepAuthority : ReplacePlayerOptions.KeepActive); + } + + // Deprecated 2024-008-09 + [Obsolete("Use ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, ReplacePlayerOptions replacePlayerOptions) instead")] + public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, bool keepAuthority = false) + { + return ReplacePlayerForConnection(conn, player, keepAuthority ? ReplacePlayerOptions.KeepAuthority : ReplacePlayerOptions.KeepActive); + } + + /// Replaces connection's player object. The old object is not destroyed. + // This does NOT change the ready state of the connection, so it can safely be used while changing scenes. + public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, uint assetId, ReplacePlayerOptions replacePlayerOptions) + { + if (GetNetworkIdentity(player, out NetworkIdentity identity)) + identity.assetId = assetId; + + return ReplacePlayerForConnection(conn, player, replacePlayerOptions); + } + + /// Replaces connection's player object. The old object is not destroyed. + // This does NOT change the ready state of the connection, so it can safely be used while changing scenes. + public static bool ReplacePlayerForConnection(NetworkConnectionToClient conn, GameObject player, ReplacePlayerOptions replacePlayerOptions) + { + if (!player.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"ReplacePlayer: playerGameObject has no NetworkIdentity. Please add a NetworkIdentity to {player}"); + return false; + } + + if (identity.connectionToClient != null && identity.connectionToClient != conn) + { + Debug.LogError($"Cannot replace player for connection. New player is already owned by a different connection{player}"); + return false; + } + + //NOTE: there can be an existing player + //Debug.Log("NetworkServer ReplacePlayer"); + + NetworkIdentity previousPlayer = conn.identity; + + conn.identity = identity; + + // Set the connection on the NetworkIdentity on the server, NetworkIdentity.SetLocalPlayer is not called on the server (it is on clients) + identity.SetClientOwner(conn); + + // special case, we are in host mode, set hasAuthority to true so that all overrides see it + if (conn is LocalConnectionToClient) + { + identity.isOwned = true; + NetworkClient.InternalAddPlayer(identity); + } + + // add connection to observers AFTER the playerController was set. + // by definition, there is nothing to observe if there is no player + // controller. + // + // IMPORTANT: do this in AddPlayerForConnection & ReplacePlayerForConnection! + SpawnObserversForConnection(conn); + + //Debug.Log($"Replacing playerGameObject object netId:{player.GetComponent().netId} asset ID {player.GetComponent().assetId}"); + + Respawn(identity); + + switch (replacePlayerOptions) + { + case ReplacePlayerOptions.KeepAuthority: + // This needs to be sent to clear isLocalPlayer on + // client while keeping hasAuthority true + SendChangeOwnerMessage(previousPlayer, conn); + break; + case ReplacePlayerOptions.KeepActive: + // This clears both isLocalPlayer and hasAuthority on client + previousPlayer.RemoveClientAuthority(); + break; + case ReplacePlayerOptions.Unspawn: + UnSpawn(previousPlayer.gameObject); + break; + case ReplacePlayerOptions.Destroy: + Destroy(previousPlayer.gameObject); + break; + } + + return true; + } + + /// Removes the player object from the connection + // destroyServerObject: Indicates whether the server object should be destroyed + // Deprecated 2024-06-06 + [Obsolete("Use RemovePlayerForConnection(NetworkConnectionToClient conn, RemovePlayerOptions removeOptions) instead")] + public static void RemovePlayerForConnection(NetworkConnectionToClient conn, bool destroyServerObject) + { + if (destroyServerObject) + RemovePlayerForConnection(conn, RemovePlayerOptions.Destroy); + else + RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn); + } + + /// Removes player object for the connection. Options to keep the object in play, unspawn it, or destroy it. + public static void RemovePlayerForConnection(NetworkConnectionToClient conn, RemovePlayerOptions removeOptions = RemovePlayerOptions.KeepActive) + { + if (conn.identity == null) return; + + switch (removeOptions) + { + case RemovePlayerOptions.KeepActive: + conn.identity.connectionToClient = null; + conn.owned.Remove(conn.identity); + SendChangeOwnerMessage(conn.identity, conn); + break; + case RemovePlayerOptions.Unspawn: + UnSpawn(conn.identity.gameObject); + break; + case RemovePlayerOptions.Destroy: + Destroy(conn.identity.gameObject); + break; + } + + conn.identity = null; + } + + // ready /////////////////////////////////////////////////////////////// + /// Flags client connection as ready (=joined world). + // When a client has signaled that it is ready, this method tells the + // server that the client is ready to receive spawned objects and state + // synchronization updates. This is usually called in a handler for the + // SYSTEM_READY message. If there is not specific action a game needs to + // take for this message, relying on the default ready handler function + // is probably fine, so this call wont be needed. + public static void SetClientReady(NetworkConnectionToClient conn) + { + // Debug.Log($"SetClientReadyInternal for conn:{conn}"); + + // set ready + conn.isReady = true; + + // client is ready to start spawning objects + if (conn.identity != null) + SpawnObserversForConnection(conn); + } + + static void SpawnObserversForConnection(NetworkConnectionToClient conn) + { + //Debug.Log($"Spawning {spawned.Count} objects for conn {conn}"); + + if (!conn.isReady) + { + // client needs to finish initializing before we can spawn objects + // otherwise it would not find them. + return; + } + + // let connection know that we are about to start spawning... + conn.Send(new ObjectSpawnStartedMessage()); + + // add connection to each nearby NetworkIdentity's observers, which + // internally sends a spawn message for each one to the connection. + foreach (NetworkIdentity identity in spawned.Values) + { + // try with far away ones in ummorpg! + if (identity.gameObject.activeSelf) //TODO this is different + { + //Debug.Log($"Sending spawn message for current server objects name:{identity.name} netId:{identity.netId} sceneId:{identity.sceneId:X}"); + + // we need to support three cases: + // - legacy system (identity has .visibility) + // - new system (networkserver has .aoi) + // - default case: no .visibility and no .aoi means add all + // connections by default) + // + // ForceHidden/ForceShown overwrite all systems so check it + // first! + + // ForceShown: add no matter what + if (identity.visibility == Visibility.ForceShown) + { + identity.AddObserver(conn); + } + // ForceHidden: don't show no matter what + else if (identity.visibility == Visibility.ForceHidden) + { + // do nothing + } + // default: legacy system / new system / no system support + else if (identity.visibility == Visibility.Default) + { + // aoi system + if (aoi != null) + { + // call OnCheckObserver + if (aoi.OnCheckObserver(identity, conn)) + identity.AddObserver(conn); + } + // no system: add all observers by default + else + { + identity.AddObserver(conn); + } + } + } + } + + // let connection know that we finished spawning, so it can call + // OnStartClient on each one (only after all were spawned, which + // is how Unity's Start() function works too) + conn.Send(new ObjectSpawnFinishedMessage()); + } + + /// Marks the client of the connection to be not-ready. + // Clients that are not ready do not receive spawned objects or state + // synchronization updates. They client can be made ready again by + // calling SetClientReady(). + public static void SetClientNotReady(NetworkConnectionToClient conn) + { + conn.isReady = false; + conn.RemoveFromObservingsObservers(); + conn.Send(new NotReadyMessage()); + } + + /// Marks all connected clients as no longer ready. + // All clients will no longer be sent state synchronization updates. The + // player's clients can call ClientManager.Ready() again to re-enter the + // ready state. This is useful when switching scenes. + public static void SetAllClientsNotReady() + { + foreach (NetworkConnectionToClient conn in connections.Values) + { + SetClientNotReady(conn); + } + } + + // show / hide for connection ////////////////////////////////////////// + internal static void ShowForConnection(NetworkIdentity identity, NetworkConnectionToClient conn) + { + if (conn.isReady) + SendSpawnMessage(identity, conn); + } + + internal static void HideForConnection(NetworkIdentity identity, NetworkConnectionToClient conn) + { + ObjectHideMessage msg = new ObjectHideMessage + { + netId = identity.netId + }; + conn.Send(msg); + } + + // spawning //////////////////////////////////////////////////////////// + internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnectionToClient conn) + { + if (identity.serverOnly) return; + + //Debug.Log($"Server SendSpawnMessage: name:{identity.name} sceneId:{identity.sceneId:X} netid:{identity.netId}"); + + // one writer for owner, one for observers + using (NetworkWriterPooled ownerWriter = NetworkWriterPool.Get(), observersWriter = NetworkWriterPool.Get()) + { + bool isOwner = identity.connectionToClient == conn; + ArraySegment payload = CreateSpawnMessagePayload(isOwner, identity, ownerWriter, observersWriter); + SpawnMessage message = new SpawnMessage + { + netId = identity.netId, + isLocalPlayer = conn.identity == identity, + isOwner = isOwner, + sceneId = identity.sceneId, + assetId = identity.assetId, + // use local values for VR support + position = identity.transform.localPosition, + rotation = identity.transform.localRotation, + scale = identity.transform.localScale, + payload = payload + }; + conn.Send(message); + } + } + + static ArraySegment CreateSpawnMessagePayload(bool isOwner, NetworkIdentity identity, NetworkWriterPooled ownerWriter, NetworkWriterPooled observersWriter) + { + // Only call SerializeAll if there are NetworkBehaviours + if (identity.NetworkBehaviours.Length == 0) + { + return default; + } + + // serialize all components with initialState = true + // (can be null if has none) + identity.SerializeServer(true, ownerWriter, observersWriter); + + // convert to ArraySegment to avoid reader allocations + // if nothing was written, .ToArraySegment returns an empty segment. + ArraySegment ownerSegment = ownerWriter.ToArraySegment(); + ArraySegment observersSegment = observersWriter.ToArraySegment(); + + // use owner segment if 'conn' owns this identity, otherwise + // use observers segment + ArraySegment payload = isOwner ? ownerSegment : observersSegment; + + return payload; + } + + internal static void SendChangeOwnerMessage(NetworkIdentity identity, NetworkConnectionToClient conn) + { + // Don't send if identity isn't spawned or only exists on server + if (identity.netId == 0 || identity.serverOnly) return; + + // Don't send if conn doesn't have the identity spawned yet + // May be excluded from the client by interest management + if (!conn.observing.Contains(identity)) return; + + //Debug.Log($"Server SendChangeOwnerMessage: name={identity.name} netid={identity.netId}"); + + conn.Send(new ChangeOwnerMessage + { + netId = identity.netId, + isOwner = identity.connectionToClient == conn, + isLocalPlayer = (conn.identity == identity && identity.connectionToClient == conn) + }); + } + + // check NetworkIdentity parent before spawning it. + // - without parent, they are spawned + // - with parent, only if the parent is active in hierarchy + // + // note that active parents may have inactive parents of their own. + // we need to check .activeInHierarchy. + // + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3330 + // https://github.com/vis2k/Mirror/issues/2778 + static bool ValidParent(NetworkIdentity identity) => + identity.transform.parent == null || + identity.transform.parent.gameObject.activeInHierarchy; + + /// Spawns NetworkIdentities in the scene on the server. + // NetworkIdentity objects in a scene are disabled by default. Calling + // SpawnObjects() causes these scene objects to be enabled and spawned. + // It is like calling NetworkServer.Spawn() for each of them. + public static bool SpawnObjects() + { + // only if server active + if (!active) + return false; + + // find all NetworkIdentities in the scene. + // all of them are disabled because of NetworkScenePostProcess. + NetworkIdentity[] identities = Resources.FindObjectsOfTypeAll(); + + // first pass: activate all scene objects + foreach (NetworkIdentity identity in identities) + { + // only spawn scene objects which haven't been spawned yet. + // SpawnObjects may be called multiple times for additive scenes. + // https://github.com/MirrorNetworking/Mirror/issues/3318 + // + // note that we even activate objects under inactive parents. + // while they are not spawned, they do need to be activated + // in order to be spawned later. so here, we don't check parents. + // https://github.com/MirrorNetworking/Mirror/issues/3330 + if (Utils.IsSceneObject(identity) && identity.netId == 0) + { + // Debug.Log($"SpawnObjects sceneId:{identity.sceneId:X} name:{identity.gameObject.name}"); + identity.gameObject.SetActive(true); + } + } + + // second pass: spawn all scene objects + foreach (NetworkIdentity identity in identities) + { + // scene objects may be children of inactive parents. + // users would put them under disabled parents to 'deactivate' them. + // those should not be used by Mirror at all. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3330 + // https://github.com/vis2k/Mirror/issues/2778 + if (Utils.IsSceneObject(identity) && identity.netId == 0 && ValidParent(identity)) + { + // pass connection so that authority is not lost when server loads a scene + // https://github.com/vis2k/Mirror/pull/2987 + Spawn(identity.gameObject, identity.connectionToClient); + } + } + + return true; + } + + /// Spawns an object and also assigns Client Authority to the specified client. + // This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object. + public static void Spawn(GameObject obj, GameObject ownerPlayer) + { + if (!ownerPlayer.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError("Player object has no NetworkIdentity"); + return; + } + + if (identity.connectionToClient == null) + { + Debug.LogError("Player object is not a player."); + return; + } + + Spawn(obj, identity.connectionToClient); + } + + static void Respawn(NetworkIdentity identity) + { + if (identity.netId == 0) + { + // If the object has not been spawned, then do a full spawn and update observers + Spawn(identity.gameObject, identity.connectionToClient); + } + else + { + // otherwise just replace his data + SendSpawnMessage(identity, identity.connectionToClient); + } + } + + /// Spawn the given game object on all clients which are ready. + // This will cause a new object to be instantiated from the registered + // prefab, or from a custom spawn function. + public static void Spawn(GameObject obj, NetworkConnectionToClient ownerConnection = null) + { + SpawnObject(obj, ownerConnection); + } + + /// Spawns an object and also assigns Client Authority to the specified client. + // This is the same as calling NetworkIdentity.AssignClientAuthority on the spawned object. + public static void Spawn(GameObject obj, uint assetId, NetworkConnectionToClient ownerConnection = null) + { + if (GetNetworkIdentity(obj, out NetworkIdentity identity)) + { + identity.assetId = assetId; + } + SpawnObject(obj, ownerConnection); + } + + static void SpawnObject(GameObject obj, NetworkConnectionToClient ownerConnection) + { + // verify if we can spawn this + if (Utils.IsPrefab(obj)) + { + Debug.LogError($"GameObject {obj.name} is a prefab, it can't be spawned. Instantiate it first.", obj); + return; + } + + if (!active) + { + Debug.LogError($"SpawnObject for {obj}, NetworkServer is not active. Cannot spawn objects without an active server.", obj); + return; + } + + if (!obj.TryGetComponent(out NetworkIdentity identity)) + { + Debug.LogError($"SpawnObject {obj} has no NetworkIdentity. Please add a NetworkIdentity to {obj}", obj); + return; + } + + if (identity.SpawnedFromInstantiate) + { + // Using Instantiate on SceneObject is not allowed, so stop spawning here + // NetworkIdentity.Awake already logs error, no need to log a second error here + return; + } + + // Spawn should only be called once per netId. + // calling it twice would lead to undefined behaviour. + // https://github.com/MirrorNetworking/Mirror/pull/3205 + if (spawned.ContainsKey(identity.netId)) + { + Debug.LogWarning($"{identity.name} [netId={identity.netId}] was already spawned.", identity.gameObject); + return; + } + + identity.connectionToClient = (NetworkConnectionToClient)ownerConnection; + + // special case to make sure hasAuthority is set + // on start server in host mode + if (ownerConnection is LocalConnectionToClient) + identity.isOwned = true; + + // NetworkServer.Unspawn sets object as inactive. + // NetworkServer.Spawn needs to set them active again in case they were previously unspawned / inactive. + identity.gameObject.SetActive(true); + + // only call OnStartServer if not spawned yet. + // check used to be in NetworkIdentity. may not be necessary anymore. + if (!identity.isServer && identity.netId == 0) + { + // configure NetworkIdentity + // this may be called in host mode, so we need to initialize + // isLocalPlayer/isClient flags too. + identity.isLocalPlayer = NetworkClient.localPlayer == identity; + identity.isClient = NetworkClient.active; + identity.isServer = true; + identity.netId = NetworkIdentity.GetNextNetworkId(); + + // add to spawned (after assigning netId) + spawned[identity.netId] = identity; + + // callback after all fields were set + identity.OnStartServer(); + } + + // Debug.Log($"SpawnObject instance ID {identity.netId} asset ID {identity.assetId}"); + + if (aoi) + { + // This calls user code which might throw exceptions + // We don't want this to leave us in bad state + try + { + aoi.OnSpawned(identity); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + RebuildObservers(identity, true); + } + + // internal Unspawn function which has the 'resetState' parameter. + // resetState calls .ResetState() on the object after unspawning. + // this is necessary for scene objects, but not for prefabs since we + // don't want to reset their isServer flags etc. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3832 + static void UnSpawnInternal(GameObject obj, bool resetState) + { + // Debug.Log($"DestroyObject instance:{identity.netId}"); + + // NetworkServer.Unspawn should only be called on server or host. + // on client, show a warning to explain what it does. + if (!active) + { + Debug.LogWarning("NetworkServer.Unspawn() called without an active server. Servers can only destroy while active, clients can only ask the server to destroy (for example, with a [Command]), after which the server may decide to destroy the object and broadcast the change to all clients."); + return; + } + + if (obj == null) + { + Debug.Log("NetworkServer.Unspawn(): object is null"); + return; + } + + if (!GetNetworkIdentity(obj, out NetworkIdentity identity)) + { + return; + } + + // only call OnRebuildObservers while active, + // not while shutting down + // (https://github.com/vis2k/Mirror/issues/2977) + if (active && aoi) + { + // This calls user code which might throw exceptions + // We don't want this to leave us in bad state + try + { + aoi.OnDestroyed(identity); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + // remove from NetworkServer (this) dictionary + spawned.Remove(identity.netId); + + identity.connectionToClient?.RemoveOwnedObject(identity); + + // send object destroy message to all observers, clear observers + SendToObservers(identity, new ObjectDestroyMessage + { + netId = identity.netId + }); + identity.ClearObservers(); + + // in host mode, call OnStopClient/OnStopLocalPlayer manually + if (NetworkClient.active && activeHost) + { + // fix: #3962 custom unspawn handler for this prefab (for prefab pools etc.) + NetworkClient.InvokeUnSpawnHandler(identity.assetId, identity.gameObject); + + if (identity.isLocalPlayer) + identity.OnStopLocalPlayer(); + + identity.OnStopClient(); + // The object may have been spawned with host client ownership, + // e.g. a pet so we need to clear hasAuthority and call + // NotifyAuthority which invokes OnStopAuthority if hasAuthority. + identity.isOwned = false; + identity.NotifyAuthority(); + + // remove from NetworkClient dictionary + NetworkClient.connection.owned.Remove(identity); + NetworkClient.spawned.Remove(identity.netId); + } + + // we are on the server. call OnStopServer. + identity.OnStopServer(); + + // finally reset the state and deactivate it + if (resetState) + { + identity.ResetState(); + identity.gameObject.SetActive(false); + } + } + + /// This takes an object that has been spawned and un-spawns it. + // The object will be removed from clients that it was spawned on, or + // the custom spawn handler function on the client will be called for + // the object. + // Unlike when calling NetworkServer.Destroy(), on the server the object + // will NOT be destroyed. This allows the server to re-use the object, + // even spawn it again later. + public static void UnSpawn(GameObject obj) => UnSpawnInternal(obj, resetState: true); + + // destroy ///////////////////////////////////////////////////////////// + /// Destroys this object and corresponding objects on all clients. + // In some cases it is useful to remove an object but not delete it on + // the server. For that, use NetworkServer.UnSpawn() instead of + // NetworkServer.Destroy(). + public static void Destroy(GameObject obj) + { + // NetworkServer.Destroy should only be called on server or host. + // on client, show a warning to explain what it does. + if (!active) + { + Debug.LogWarning("NetworkServer.Destroy() called without an active server. Servers can only destroy while active, clients can only ask the server to destroy (for example, with a [Command]), after which the server may decide to destroy the object and broadcast the change to all clients."); + return; + } + + if (obj == null) + { + Debug.Log("NetworkServer.Destroy(): object is null"); + return; + } + + // get the NetworkIdentity component first + if (!GetNetworkIdentity(obj, out NetworkIdentity identity)) + { + Debug.LogWarning($"NetworkServer.Destroy() called on {obj.name} which doesn't have a NetworkIdentity component."); + return; + } + + // is this a scene object? + // then we simply unspawn & reset it so it can still be spawned again. + // we never destroy scene objects on server or on client, since once + // they are gone, they are gone forever and can't be instantiate again. + // for example, server may Destroy() a scene object and once a match + // restarts, the scene objects would be gone from the new match. + if (identity.sceneId != 0) + { + UnSpawnInternal(obj, resetState: true); + } + // is this a prefab? + // then we destroy it completely. + else + { + // unspawn without calling ResetState. + // otherwise isServer/isClient flags might be reset in OnDestroy. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3832 + UnSpawnInternal(obj, resetState: false); + identity.destroyCalled = true; + + // Destroy if application is running + if (Application.isPlaying) + { + UnityEngine.Object.Destroy(obj); + } + // Destroy can't be used in Editor during tests. use DestroyImmediate. + else + { + GameObject.DestroyImmediate(obj); + } + } + } + + // interest management ///////////////////////////////////////////////// + // Helper function to add all server connections as observers. + // This is used if none of the components provides their own + // OnRebuildObservers function. + // rebuild observers default method (no AOI) - adds all connections + static void RebuildObserversDefault(NetworkIdentity identity, bool initialize) + { + // only add all connections when rebuilding the first time. + // second time we just keep them without rebuilding anything. + if (initialize) + { + // not force hidden? + if (identity.visibility != Visibility.ForceHidden) + { + AddAllReadyServerConnectionsToObservers(identity); + } + else if (identity.connectionToClient != null) + { + // force hidden, but add owner connection + identity.AddObserver(identity.connectionToClient); + } + } + } + + internal static void AddAllReadyServerConnectionsToObservers(NetworkIdentity identity) + { + // add all server connections + foreach (NetworkConnectionToClient conn in connections.Values) + { + // only if authenticated (don't send to people during logins) + if (conn.isReady) + identity.AddObserver(conn); + } + + // add local host connection (if any) + if (localConnection != null && localConnection.isReady) + { + identity.AddObserver(localConnection); + } + } + + // RebuildObservers does a local rebuild for the NetworkIdentity. + // This causes the set of players that can see this object to be rebuild. + // + // IMPORTANT: + // => global rebuild would be more simple, BUT + // => local rebuild is way faster for spawn/despawn because we can + // simply rebuild a select NetworkIdentity only + // => having both .observers and .observing is necessary for local + // rebuilds + // + // in other words, this is the perfect solution even though it's not + // completely simple (due to .observers & .observing) + // + // Mirror maintains .observing automatically in the background. best of + // both worlds without any worrying now! + public static void RebuildObservers(NetworkIdentity identity, bool initialize) + { + // if there is no interest management system, + // or if 'force shown' then add all connections + if (aoi == null || identity.visibility == Visibility.ForceShown) + { + RebuildObserversDefault(identity, initialize); + } + // otherwise let interest management system rebuild + else + { + aoi.Rebuild(identity, initialize); + } + } + + + // broadcasting //////////////////////////////////////////////////////// + // helper function to get the right serialization for a connection + static NetworkWriter SerializeForConnection(NetworkIdentity identity, NetworkConnectionToClient connection) + { + // get serialization for this entity (cached) + // IMPORTANT: int tick avoids floating point inaccuracy over days/weeks + NetworkIdentitySerialization serialization = identity.GetServerSerializationAtTick(Time.frameCount); + + // is this entity owned by this connection? + bool owned = identity.connectionToClient == connection; + + // send serialized data + // owner writer if owned + if (owned) + { + // was it dirty / did we actually serialize anything? + if (serialization.ownerWriter.Position > 0) + return serialization.ownerWriter; + } + // observers writer if not owned + else + { + // was it dirty / did we actually serialize anything? + if (serialization.observersWriter.Position > 0) + return serialization.observersWriter; + } + + // nothing was serialized + return null; + } + + // helper function to broadcast the world to a connection + static void BroadcastToConnection(NetworkConnectionToClient connection) + { + // for each entity that this connection is seeing + bool hasNull = false; + foreach (NetworkIdentity identity in connection.observing) + { + // make sure it's not null or destroyed. + // (which can happen if someone uses + // GameObject.Destroy instead of + // NetworkServer.Destroy) + if (identity != null) + { + // get serialization for this entity viewed by this connection + // (if anything was serialized this time) + NetworkWriter serialization = SerializeForConnection(identity, connection); + if (serialization != null) + { + EntityStateMessage message = new EntityStateMessage + { + netId = identity.netId, + payload = serialization.ToArraySegment() + }; + connection.Send(message); + } + } + // spawned list should have no null entries because we + // always call Remove in OnObjectDestroy everywhere. + // if it does have null then someone used + // GameObject.Destroy instead of NetworkServer.Destroy. + else + { + hasNull = true; + Debug.LogWarning($"Found 'null' entry in observing list for connectionId={connection.connectionId}. Please call NetworkServer.Destroy to destroy networked objects. Don't use GameObject.Destroy."); + } + } + + // recover from null entries. + // otherwise every broadcast will spam the warning and slow down performance until restart. + if (hasNull) connection.observing.RemoveWhere(identity => identity == null); + } + + // helper function to check a connection for inactivity and disconnect if necessary + // returns true if disconnected + static bool DisconnectIfInactive(NetworkConnectionToClient connection) + { + // check for inactivity + if (disconnectInactiveConnections && + !connection.IsAlive(disconnectInactiveTimeout)) + { + Debug.LogWarning($"Disconnecting {connection} for inactivity!"); + connection.Disconnect(); + return true; + } + return false; + } + + // NetworkLateUpdate called after any Update/FixedUpdate/LateUpdate + // (we add this to the UnityEngine in NetworkLoop) + // internal for tests + internal static readonly List connectionsCopy = + new List(); + + static void Broadcast() + { + // copy all connections into a helper collection so that + // OnTransportDisconnected can be called while iterating. + // -> OnTransportDisconnected removes from the collection + // -> which would throw 'can't modify while iterating' errors + // => see also: https://github.com/vis2k/Mirror/issues/2739 + // (copy nonalloc) + // TODO remove this when we move to 'lite' transports with only + // socket send/recv later. + connectionsCopy.Clear(); + connections.Values.CopyTo(connectionsCopy); + + // go through all connections + foreach (NetworkConnectionToClient connection in connectionsCopy) + { + // check for inactivity. disconnects if necessary. + if (DisconnectIfInactive(connection)) + continue; + + // has this connection joined the world yet? + // for each READY connection: + // pull in UpdateVarsMessage for each entity it observes + if (connection.isReady) + { + // send time for snapshot interpolation every sendInterval. + // BroadcastToConnection() may not send if nothing is new. + // + // sent over unreliable. + // NetworkTime / Transform both use unreliable. + // + // make sure Broadcast() is only called every sendInterval, + // even if targetFrameRate isn't set in host mode (!) + // (done via AccurateInterval) + connection.Send(new TimeSnapshotMessage(), Channels.Unreliable); + + // broadcast world state to this connection + BroadcastToConnection(connection); + } + + // update connection to flush out batched messages + connection.Update(); + } + } + + // update ////////////////////////////////////////////////////////////// + // NetworkEarlyUpdate called before any Update/FixedUpdate + // (we add this to the UnityEngine in NetworkLoop) + internal static void NetworkEarlyUpdate() + { + // measure update time for profiling. + if (active) + { + earlyUpdateDuration.Begin(); + fullUpdateDuration.Begin(); + } + + // process all incoming messages first before updating the world + if (Transport.active != null) + Transport.active.ServerEarlyUpdate(); + + // step each connection's local time interpolation in early update. + foreach (NetworkConnectionToClient connection in connections.Values) + connection.UpdateTimeInterpolation(); + + if (active) earlyUpdateDuration.End(); + } + + internal static void NetworkLateUpdate() + { + if (active) + { + // measure update time for profiling. + lateUpdateDuration.Begin(); + + // only broadcast world if active + // broadcast every sendInterval. + // AccurateInterval to avoid update frequency inaccuracy issues: + // https://github.com/vis2k/Mirror/pull/3153 + // + // for example, host mode server doesn't set .targetFrameRate. + // Broadcast() would be called every tick. + // snapshots might be sent way too often, etc. + // + // during tests, we always call Broadcast() though. + // + // also important for syncInterval=0 components like + // NetworkTransform, so they can sync on same interval as time + // snapshots _but_ not every single tick. + // Unity 2019 doesn't have Time.timeAsDouble yet + bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime); + if (!Application.isPlaying || sendIntervalElapsed) + Broadcast(); + } + + // process all outgoing messages after updating the world + // (even if not active. still want to process disconnects etc.) + if (Transport.active != null) + Transport.active.ServerLateUpdate(); + + // measure actual tick rate every second. + if (active) + { + ++actualTickRateCounter; + + // NetworkTime.localTime has defines for 2019 / 2020 compatibility + if (NetworkTime.localTime >= actualTickRateStart + 1) + { + // calculate avg by exact elapsed time. + // assuming 1s wouldn't be accurate, usually a few more ms passed. + float elapsed = (float)(NetworkTime.localTime - actualTickRateStart); + actualTickRate = Mathf.RoundToInt(actualTickRateCounter / elapsed); + actualTickRateStart = NetworkTime.localTime; + actualTickRateCounter = 0; + } + + // measure total update time. including transport. + // because in early update, transport update calls handlers. + lateUpdateDuration.End(); + fullUpdateDuration.End(); + } + } + } +} diff --git a/Assets/Mirror/Core/NetworkServer.cs.meta b/Assets/Mirror/Core/NetworkServer.cs.meta new file mode 100644 index 0000000..84d41e8 --- /dev/null +++ b/Assets/Mirror/Core/NetworkServer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a5f5ec068f5604c32b160bc49ee97b75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkServer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkStartPosition.cs b/Assets/Mirror/Core/NetworkStartPosition.cs new file mode 100644 index 0000000..e11029b --- /dev/null +++ b/Assets/Mirror/Core/NetworkStartPosition.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +namespace Mirror +{ + /// Start position for player spawning, automatically registers itself in the NetworkManager. + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Start Position")] + [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-start-position")] + public class NetworkStartPosition : MonoBehaviour + { + public void Awake() + { + NetworkManager.RegisterStartPosition(transform); + } + + public void OnDestroy() + { + NetworkManager.UnRegisterStartPosition(transform); + } + } +} diff --git a/Assets/Mirror/Core/NetworkStartPosition.cs.meta b/Assets/Mirror/Core/NetworkStartPosition.cs.meta new file mode 100644 index 0000000..64a7fe4 --- /dev/null +++ b/Assets/Mirror/Core/NetworkStartPosition.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 41f84591ce72545258ea98cb7518d8b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkStartPosition.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkTime.cs b/Assets/Mirror/Core/NetworkTime.cs new file mode 100644 index 0000000..6319970 --- /dev/null +++ b/Assets/Mirror/Core/NetworkTime.cs @@ -0,0 +1,243 @@ +// NetworkTime now uses NetworkClient's snapshot interpolated timeline. +// this gives ideal results & ensures everything is on the same timeline. +// previously, NetworkTransforms were on separate timelines. +// +// however, some of the old NetworkTime code remains for ping time (rtt). +// some users may still be using that. +using System; +using System.Runtime.CompilerServices; +using UnityEngine; +#if !UNITY_2020_3_OR_NEWER +using Stopwatch = System.Diagnostics.Stopwatch; +#endif + +namespace Mirror +{ + /// Synchronizes server time to clients. + public static class NetworkTime + { + /// Ping message interval, used to calculate latency / RTT and predicted time. + // 2s was enough to get a good average RTT. + // for prediction, we want to react to latency changes more rapidly. + const float DefaultPingInterval = 0.1f; // for resets + public static float PingInterval = DefaultPingInterval; + + /// Average out the last few results from Ping + // const because it's used immediately in _rtt constructor. + public const int PingWindowSize = 50; // average over 50 * 100ms = 5s + + static double lastPingTime; + + static ExponentialMovingAverage _rtt = new ExponentialMovingAverage(PingWindowSize); + + /// Returns double precision clock time _in this system_, unaffected by the network. +#if UNITY_2020_3_OR_NEWER + public static double localTime + { + // NetworkTime uses unscaled time and ignores Time.timeScale. + // fixes Time.timeScale getting server & client time out of sync: + // https://github.com/MirrorNetworking/Mirror/issues/3409 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Time.unscaledTimeAsDouble; + } +#else + // need stopwatch for older Unity versions, but it's quite slow. + // CAREFUL: unlike Time.time, the stopwatch time is not a FRAME time. + // it changes during the frame, so we have an extra step to "cache" it in EarlyUpdate. + static readonly Stopwatch stopwatch = new Stopwatch(); + static NetworkTime() => stopwatch.Start(); + static double localFrameTime; + public static double localTime => localFrameTime; +#endif + + /// The time in seconds since the server started. + // via global NetworkClient snapshot interpolated timeline (if client). + // on server, this is simply Time.timeAsDouble. + // + // I measured the accuracy of float and I got this: + // for the same day, accuracy is better than 1 ms + // after 1 day, accuracy goes down to 7 ms + // after 10 days, accuracy is 61 ms + // after 30 days , accuracy is 238 ms + // after 60 days, accuracy is 454 ms + // in other words, if the server is running for 2 months, + // and you cast down to float, then the time will jump in 0.4s intervals. + public static double time + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => NetworkServer.active + ? localTime + : NetworkClient.localTimeline; + } + + // prediction ////////////////////////////////////////////////////////// + // NetworkTime.time is server time, behind by bufferTime. + // for prediction, we want server time, ahead by latency. + // so that client inputs at predictedTime=2 arrive on server at time=2. + // the more accurate this is, the more closesly will corrections be + // be applied and the less jitter we will see. + // + // we'll use a two step process to calculate predicted time: + // 1. move snapshot interpolated time to server time, without being behind by bufferTime + // 2. constantly send this time to server (included in ping message) + // server replies with how far off it was. + // client averages that offset and applies it to predictedTime to get ever closer. + // + // this is also very easy to test & verify: + // - add LatencySimulation with 50ms latency + // - log predictionError on server in OnServerPing, see if it gets closer to 0 + // + // credits: FakeByte, imer, NinjaKickja, mischa + // const because it's used immediately in _predictionError constructor. + + static int PredictionErrorWindowSize = 20; // average over 20 * 100ms = 2s + static ExponentialMovingAverage _predictionErrorUnadjusted = new ExponentialMovingAverage(PredictionErrorWindowSize); + public static double predictionErrorUnadjusted => _predictionErrorUnadjusted.Value; + public static double predictionErrorAdjusted { get; private set; } // for debugging + + /// Predicted timeline in order for client inputs to be timestamped with the exact time when they will most likely arrive on the server. This is the basis for all prediction like PredictedRigidbody. + // on client, this is based on localTime (aka Time.time) instead of the snapshot interpolated timeline. + // this gives much better and immediately accurate results. + // -> snapshot interpolation timeline tries to emulate a server timeline without hard offset corrections. + // -> predictedTime does have hard offset corrections, so might as well use Time.time directly for this. + // + // note that predictedTime over unreliable is enough! + // even with reliable components, it gives better results than if we were + // to implemented predictedTime over reliable channel. + public static double predictedTime + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => NetworkServer.active + ? localTime // server always uses it's own timeline + : localTime + predictionErrorUnadjusted; // add the offset that the server told us we are off by + } + //////////////////////////////////////////////////////////////////////// + + /// Clock difference in seconds between the client and the server. Always 0 on server. + // original implementation used 'client - server' time. keep it this way. + // TODO obsolete later. people shouldn't worry about this. + public static double offset => localTime - time; + + /// Round trip time (in seconds) that it takes a message to go client->server->client. + public static double rtt => _rtt.Value; + + /// Round trip time variance aka jitter, in seconds. + // "rttVariance" instead of "rttVar" for consistency with older versions. + public static double rttVariance => _rtt.Variance; + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod] + public static void ResetStatics() + { + PingInterval = DefaultPingInterval; + lastPingTime = 0; + _rtt = new ExponentialMovingAverage(PingWindowSize); +#if !UNITY_2020_3_OR_NEWER + stopwatch.Restart(); +#endif + } + + internal static void UpdateClient() + { + // localTime (double) instead of Time.time for accuracy over days + if (localTime >= lastPingTime + PingInterval) + SendPing(); + } + + // Separate method so we can call it from NetworkClient directly. + internal static void SendPing() + { + // send raw predicted time without the offset applied yet. + // we then apply the offset to it after. + NetworkPingMessage pingMessage = new NetworkPingMessage + ( + localTime, + predictedTime + ); + NetworkClient.Send(pingMessage, Channels.Unreliable); + lastPingTime = localTime; + } + + // client rtt calculation ////////////////////////////////////////////// + // executed at the server when we receive a ping message + // reply with a pong containing the time from the client + // and time from the server + internal static void OnServerPing(NetworkConnectionToClient conn, NetworkPingMessage message) + { + // calculate the prediction offset that the client needs to apply to unadjusted time to reach server time. + // this will be sent back to client for corrections. + double unadjustedError = localTime - message.localTime; + + // to see how well the client's final prediction worked, compare with adjusted time. + // this is purely for debugging. + // >0 means: server is ... seconds ahead of client's prediction (good if small) + // <0 means: server is ... seconds behind client's prediction. + // in other words, client is predicting too far ahead (not good) + double adjustedError = localTime - message.predictedTimeAdjusted; + // Debug.Log($"[Server] unadjustedError:{(unadjustedError*1000):F1}ms adjustedError:{(adjustedError*1000):F1}ms"); + + // Debug.Log($"OnServerPing conn:{conn}"); + NetworkPongMessage pongMessage = new NetworkPongMessage + ( + message.localTime, + unadjustedError, + adjustedError + ); + conn.Send(pongMessage, Channels.Unreliable); + } + + // Executed at the client when we receive a Pong message + // find out how long it took since we sent the Ping + // and update time offset & prediction offset. + internal static void OnClientPong(NetworkPongMessage message) + { + // prevent attackers from sending timestamps which are in the future + if (message.localTime > localTime) return; + + // how long did this message take to come back + double newRtt = localTime - message.localTime; + _rtt.Add(newRtt); + + // feed unadjusted prediction error into our exponential moving average + // store adjusted prediction error for debug / GUI purposes + _predictionErrorUnadjusted.Add(message.predictionErrorUnadjusted); + predictionErrorAdjusted = message.predictionErrorAdjusted; + // Debug.Log($"[Client] predictionError avg={(_predictionErrorUnadjusted.Value*1000):F1} ms"); + } + + // server rtt calculation ////////////////////////////////////////////// + // Executed at the client when we receive a ping message from the server. + // in other words, this is for server sided ping + rtt calculation. + // reply with a pong containing the time from the server + internal static void OnClientPing(NetworkPingMessage message) + { + // Debug.Log($"OnClientPing conn:{conn}"); + NetworkPongMessage pongMessage = new NetworkPongMessage + ( + message.localTime, + 0, 0 // server doesn't predict + ); + NetworkClient.Send(pongMessage, Channels.Unreliable); + } + + // Executed at the server when we receive a Pong message back. + // find out how long it took since we sent the Ping + // and update time offset + internal static void OnServerPong(NetworkConnectionToClient conn, NetworkPongMessage message) + { + // prevent attackers from sending timestamps which are in the future + if (message.localTime > localTime) return; + + // how long did this message take to come back + double newRtt = localTime - message.localTime; + conn._rtt.Add(newRtt); + } + + internal static void EarlyUpdate() + { +#if !UNITY_2020_3_OR_NEWER + localFrameTime = stopwatch.Elapsed.TotalSeconds; +#endif + } + } +} diff --git a/Assets/Mirror/Core/NetworkTime.cs.meta b/Assets/Mirror/Core/NetworkTime.cs.meta new file mode 100644 index 0000000..0049ede --- /dev/null +++ b/Assets/Mirror/Core/NetworkTime.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 09a0c241fc4a5496dbf4a0ab6e9a312c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkTime.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkWriter.cs b/Assets/Mirror/Core/NetworkWriter.cs new file mode 100644 index 0000000..7ecf126 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriter.cs @@ -0,0 +1,249 @@ +using System; +using System.Runtime.CompilerServices; +using System.Text; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; + +namespace Mirror +{ + /// Network Writer for most simple types like floats, ints, buffers, structs, etc. Use NetworkWriterPool.GetReader() to avoid allocations. + public class NetworkWriter + { + // the limit of ushort is so we can write string size prefix as only 2 bytes. + // -1 so we can still encode 'null' into it too. + public const ushort MaxStringLength = ushort.MaxValue - 1; + + // create writer immediately with it's own buffer so no one can mess with it and so that we can resize it. + // note: BinaryWriter allocates too much, so we only use a MemoryStream + // => 1500 bytes by default because on average, most packets will be <= MTU + public const int DefaultCapacity = 1500; + internal byte[] buffer = new byte[DefaultCapacity]; + + /// Next position to write to the buffer + public int Position; + + /// Current capacity. Automatically resized if necessary. + public int Capacity => buffer.Length; + + // cache encoding for WriteString instead of creating it each time. + // 1000 readers before: 1MB GC, 30ms + // 1000 readers after: 0.8MB GC, 18ms + // not(!) static for thread safety. + // + // throwOnInvalidBytes is true. + // writer should throw and user should fix if this ever happens. + // unlike reader, which needs to expect it to happen from attackers. + internal readonly UTF8Encoding encoding = new UTF8Encoding(false, true); + + /// Reset both the position and length of the stream + // Leaves the capacity the same so that we can reuse this writer without + // extra allocations + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reset() + { + Position = 0; + } + + // NOTE that our runtime resizing comes at no extra cost because: + // 1. 'has space' checks are necessary even for fixed sized writers. + // 2. all writers will eventually be large enough to stop resizing. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void EnsureCapacity(int value) + { + if (buffer.Length < value) + { + int capacity = Math.Max(value, buffer.Length * 2); + Array.Resize(ref buffer, capacity); + } + } + + /// Copies buffer until 'Position' to a new array. + // Try to use ToArraySegment instead to avoid allocations! + public byte[] ToArray() + { + byte[] data = new byte[Position]; + Array.ConstrainedCopy(buffer, 0, data, 0, Position); + return data; + } + + /// Returns allocation-free ArraySegment until 'Position'. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ArraySegment ToArraySegment() => + new ArraySegment(buffer, 0, Position); + + // implicit conversion for convenience + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ArraySegment(NetworkWriter w) => + w.ToArraySegment(); + + // WriteBlittable from DOTSNET. + // this is extremely fast, but only works for blittable types. + // + // Benchmark: + // WriteQuaternion x 100k, Macbook Pro 2015 @ 2.2Ghz, Unity 2018 LTS (debug mode) + // + // | Median | Min | Max | Avg | Std | (ms) + // before | 30.35 | 29.86 | 48.99 | 32.54 | 4.93 | + // blittable* | 5.69 | 5.52 | 27.51 | 7.78 | 5.65 | + // + // * without IsBlittable check + // => 4-6x faster! + // + // WriteQuaternion x 100k, Macbook Pro 2015 @ 2.2Ghz, Unity 2020.1 (release mode) + // + // | Median | Min | Max | Avg | Std | (ms) + // before | 9.41 | 8.90 | 23.02 | 10.72 | 3.07 | + // blittable* | 1.48 | 1.40 | 16.03 | 2.60 | 2.71 | + // + // * without IsBlittable check + // => 6x faster! + // + // Note: + // WriteBlittable assumes same endianness for server & client. + // All Unity 2018+ platforms are little endian. + // => run NetworkWriterTests.BlittableOnThisPlatform() to verify! + // + // This is not safe to expose to random structs. + // * StructLayout.Sequential is the default, which is safe. + // if the struct contains a reference type, it is converted to Auto. + // but since all structs here are unmanaged blittable, it's safe. + // see also: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind?view=netframework-4.8#system-runtime-interopservices-layoutkind-sequential + // * StructLayout.Pack depends on CPU word size. + // this may be different 4 or 8 on some ARM systems, etc. + // this is not safe, and would cause bytes/shorts etc. to be padded. + // see also: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.structlayoutattribute.pack?view=net-6.0 + // * If we force pack all to '1', they would have no padding which is + // great for bandwidth. but on some android systems, CPU can't read + // unaligned memory. + // see also: https://github.com/vis2k/Mirror/issues/3044 + // * The only option would be to force explicit layout with multiples + // of word size. but this requires lots of weaver checking and is + // still questionable (IL2CPP etc.). + // + // Note: inlining WriteBlittable is enough. don't inline WriteInt etc. + // we don't want WriteBlittable to be copied in place everywhere. + internal unsafe void WriteBlittable(T value) + where T : unmanaged + { + // check if blittable for safety +#if UNITY_EDITOR + if (!UnsafeUtility.IsBlittable(typeof(T))) + { + Debug.LogError($"{typeof(T)} is not blittable!"); + return; + } +#endif + // calculate size + // sizeof(T) gets the managed size at compile time. + // Marshal.SizeOf gets the unmanaged size at runtime (slow). + // => our 1mio writes benchmark is 6x slower with Marshal.SizeOf + // => for blittable types, sizeof(T) is even recommended: + // https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices + int size = sizeof(T); + + // ensure capacity + // NOTE that our runtime resizing comes at no extra cost because: + // 1. 'has space' checks are necessary even for fixed sized writers. + // 2. all writers will eventually be large enough to stop resizing. + EnsureCapacity(Position + size); + + // write blittable + fixed (byte* ptr = &buffer[Position]) + { +#if UNITY_ANDROID + // on some android systems, assigning *(T*)ptr throws a NRE if + // the ptr isn't aligned (i.e. if Position is 1,2,3,5, etc.). + // here we have to use memcpy. + // + // => we can't get a pointer of a struct in C# without + // marshalling allocations + // => instead, we stack allocate an array of type T and use that + // => stackalloc avoids GC and is very fast. it only works for + // value types, but all blittable types are anyway. + // + // this way, we can still support blittable reads on android. + // see also: https://github.com/vis2k/Mirror/issues/3044 + // (solution discovered by AIIO, FakeByte, mischa) + T* valueBuffer = stackalloc T[1]{value}; + UnsafeUtility.MemCpy(ptr, valueBuffer, size); +#else + // cast buffer to T* pointer, then assign value to the area + *(T*)ptr = value; +#endif + } + Position += size; + } + + // blittable'?' template for code reuse + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void WriteBlittableNullable(T? value) + where T : unmanaged + { + // bool isn't blittable. write as byte. + WriteByte((byte)(value.HasValue ? 0x01 : 0x00)); + + // only write value if exists. saves bandwidth. + if (value.HasValue) + WriteBlittable(value.Value); + } + + public void WriteByte(byte value) => WriteBlittable(value); + + // for byte arrays with consistent size, where the reader knows how many to read + // (like a packet opcode that's always the same) + public void WriteBytes(byte[] array, int offset, int count) + { + EnsureCapacity(Position + count); + Array.ConstrainedCopy(array, offset, this.buffer, Position, count); + Position += count; + } + // write an unsafe byte* array. + // useful for bit tree compression, etc. + public unsafe bool WriteBytes(byte* ptr, int offset, int size) + { + EnsureCapacity(Position + size); + + fixed (byte* destination = &buffer[Position]) + { + // write 'size' bytes at position + // 10 mio writes: 868ms + // Array.Copy(value.Array, value.Offset, buffer, Position, value.Count); + // 10 mio writes: 775ms + // Buffer.BlockCopy(value.Array, value.Offset, buffer, Position, value.Count); + // 10 mio writes: 637ms + UnsafeUtility.MemCpy(destination, ptr + offset, size); + } + + Position += size; + return true; + } + + /// Writes any type that mirror supports. Uses weaver populated Writer(T).write. + public void Write(T value) + { + Action writeDelegate = Writer.write; + if (writeDelegate == null) + { + Debug.LogError($"No writer found for {typeof(T)}. This happens either if you are missing a NetworkWriter extension for your custom type, or if weaving failed. Try to reimport a script to weave again."); + } + else + { + writeDelegate(this, value); + } + } + + // print with buffer content for easier debugging. + // [content, position / capacity]. + // showing "position / space" would be too confusing. + public override string ToString() => + $"[{ToArraySegment().ToHexString()} @ {Position}/{Capacity}]"; + } + + /// Helper class that weaver populates with all writer types. + // Note that c# creates a different static variable for each type + // -> Weaver.ReaderWriterProcessor.InitializeReaderAndWriters() populates it + public static class Writer + { + public static Action write; + } +} diff --git a/Assets/Mirror/Core/NetworkWriter.cs.meta b/Assets/Mirror/Core/NetworkWriter.cs.meta new file mode 100644 index 0000000..17cba61 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriter.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 48d2207bcef1f4477b624725f075f9bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkWriter.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkWriterExtensions.cs b/Assets/Mirror/Core/NetworkWriterExtensions.cs new file mode 100644 index 0000000..1f6588f --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterExtensions.cs @@ -0,0 +1,471 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // Mirror's Weaver automatically detects all NetworkWriter function types, + // but they do all need to be extensions. + public static class NetworkWriterExtensions + { + public static void WriteByte(this NetworkWriter writer, byte value) => writer.WriteBlittable(value); + public static void WriteByteNullable(this NetworkWriter writer, byte? value) => writer.WriteBlittableNullable(value); + + public static void WriteSByte(this NetworkWriter writer, sbyte value) => writer.WriteBlittable(value); + public static void WriteSByteNullable(this NetworkWriter writer, sbyte? value) => writer.WriteBlittableNullable(value); + + // char is not blittable. convert to ushort. + public static void WriteChar(this NetworkWriter writer, char value) => writer.WriteBlittable((ushort)value); + public static void WriteCharNullable(this NetworkWriter writer, char? value) => writer.WriteBlittableNullable((ushort?)value); + + // bool is not blittable. convert to byte. + public static void WriteBool(this NetworkWriter writer, bool value) => writer.WriteBlittable((byte)(value ? 1 : 0)); + public static void WriteBoolNullable(this NetworkWriter writer, bool? value) => writer.WriteBlittableNullable(value.HasValue ? ((byte)(value.Value ? 1 : 0)) : new byte?()); + + public static void WriteShort(this NetworkWriter writer, short value) => writer.WriteBlittable(value); + public static void WriteShortNullable(this NetworkWriter writer, short? value) => writer.WriteBlittableNullable(value); + + public static void WriteUShort(this NetworkWriter writer, ushort value) => writer.WriteBlittable(value); + public static void WriteUShortNullable(this NetworkWriter writer, ushort? value) => writer.WriteBlittableNullable(value); + + public static void WriteInt(this NetworkWriter writer, int value) => writer.WriteBlittable(value); + public static void WriteIntNullable(this NetworkWriter writer, int? value) => writer.WriteBlittableNullable(value); + + public static void WriteUInt(this NetworkWriter writer, uint value) => writer.WriteBlittable(value); + public static void WriteUIntNullable(this NetworkWriter writer, uint? value) => writer.WriteBlittableNullable(value); + + public static void WriteLong(this NetworkWriter writer, long value) => writer.WriteBlittable(value); + public static void WriteLongNullable(this NetworkWriter writer, long? value) => writer.WriteBlittableNullable(value); + + public static void WriteULong(this NetworkWriter writer, ulong value) => writer.WriteBlittable(value); + public static void WriteULongNullable(this NetworkWriter writer, ulong? value) => writer.WriteBlittableNullable(value); + + // WriteInt/UInt/Long/ULong writes full bytes by default. + // define additional "VarInt" versions that Weaver will automatically prefer. + // 99% of the time [SyncVar] ints are small values, which makes this very much worth it. + [WeaverPriority] public static void WriteVarInt(this NetworkWriter writer, int value) => Compression.CompressVarInt(writer, value); + [WeaverPriority] public static void WriteVarUInt(this NetworkWriter writer, uint value) => Compression.CompressVarUInt(writer, value); + [WeaverPriority] public static void WriteVarLong(this NetworkWriter writer, long value) => Compression.CompressVarInt(writer, value); + [WeaverPriority] public static void WriteVarULong(this NetworkWriter writer, ulong value) => Compression.CompressVarUInt(writer, value); + + public static void WriteFloat(this NetworkWriter writer, float value) => writer.WriteBlittable(value); + public static void WriteFloatNullable(this NetworkWriter writer, float? value) => writer.WriteBlittableNullable(value); + + public static void WriteDouble(this NetworkWriter writer, double value) => writer.WriteBlittable(value); + public static void WriteDoubleNullable(this NetworkWriter writer, double? value) => writer.WriteBlittableNullable(value); + + public static void WriteDecimal(this NetworkWriter writer, decimal value) => writer.WriteBlittable(value); + public static void WriteDecimalNullable(this NetworkWriter writer, decimal? value) => writer.WriteBlittableNullable(value); + + public static void WriteHalf(this NetworkWriter writer, Half value) => writer.WriteUShort(value._value); + + public static void WriteString(this NetworkWriter writer, string value) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + if (value == null) + { + writer.WriteUShort(0); + return; + } + + // WriteString copies into the buffer manually. + // need to ensure capacity here first, manually. + int maxSize = writer.encoding.GetMaxByteCount(value.Length); + writer.EnsureCapacity(writer.Position + 2 + maxSize); // 2 bytes position + N bytes encoding + + // encode it into the buffer first. + // reserve 2 bytes for header after we know how much was written. + int written = writer.encoding.GetBytes(value, 0, value.Length, writer.buffer, writer.Position + 2); + + // check if within max size, otherwise Reader can't read it. + if (written > NetworkWriter.MaxStringLength) + throw new IndexOutOfRangeException($"NetworkWriter.WriteString - Value too long: {written} bytes. Limit: {NetworkWriter.MaxStringLength} bytes"); + + // .Position is unchanged, so fill in the size header now. + // we already ensured that max size fits into ushort.max-1. + writer.WriteUShort(checked((ushort)(written + 1))); // Position += 2 + + // now update position by what was written above + writer.Position += written; + } + + // Weaver needs a write function with just one byte[] parameter + // (we don't name it .Write(byte[]) because it's really a WriteBytesAndSize since we write size / null info too) + public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer) + { + // buffer might be null, so we can't use .Length in that case + writer.WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0); + } + + // for byte arrays with dynamic size, where the reader doesn't know how many will come + // (like an inventory with different items etc.) + public static void WriteBytesAndSize(this NetworkWriter writer, byte[] buffer, int offset, int count) + { + // null is supported because [SyncVar]s might be structs with null byte[] arrays. + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + if (buffer == null) + { + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, 0u); + // writer.WriteUInt(0u); + return; + } + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, checked((uint)count) + 1u); + // writer.WriteUInt(checked((uint)count) + 1u); + writer.WriteBytes(buffer, offset, count); + } + + // writes ArraySegment of byte (most common type) and size header + public static void WriteArraySegmentAndSize(this NetworkWriter writer, ArraySegment segment) + { + writer.WriteBytesAndSize(segment.Array, segment.Offset, segment.Count); + } + + // writes ArraySegment of any type, and size header + public static void WriteArraySegment(this NetworkWriter writer, ArraySegment segment) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + // + // ArraySegment technically can't be null, but users may call: + // - WriteArraySegment + // - ReadArray + // in which case ReadArray needs null support. both need to be compatible. + int count = segment.Count; + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, checked((uint)count) + 1u); + // writer.WriteUInt(checked((uint)count) + 1u); + for (int i = 0; i < count; i++) + { + writer.Write(segment.Array[segment.Offset + i]); + } + } + + public static void WriteVector2(this NetworkWriter writer, Vector2 value) => writer.WriteBlittable(value); + public static void WriteVector2Nullable(this NetworkWriter writer, Vector2? value) => writer.WriteBlittableNullable(value); + + public static void WriteVector3(this NetworkWriter writer, Vector3 value) => writer.WriteBlittable(value); + public static void WriteVector3Nullable(this NetworkWriter writer, Vector3? value) => writer.WriteBlittableNullable(value); + + public static void WriteVector4(this NetworkWriter writer, Vector4 value) => writer.WriteBlittable(value); + public static void WriteVector4Nullable(this NetworkWriter writer, Vector4? value) => writer.WriteBlittableNullable(value); + + public static void WriteVector2Int(this NetworkWriter writer, Vector2Int value) => writer.WriteBlittable(value); + public static void WriteVector2IntNullable(this NetworkWriter writer, Vector2Int? value) => writer.WriteBlittableNullable(value); + + public static void WriteVector3Int(this NetworkWriter writer, Vector3Int value) => writer.WriteBlittable(value); + public static void WriteVector3IntNullable(this NetworkWriter writer, Vector3Int? value) => writer.WriteBlittableNullable(value); + + public static void WriteColor(this NetworkWriter writer, Color value) => writer.WriteBlittable(value); + public static void WriteColorNullable(this NetworkWriter writer, Color? value) => writer.WriteBlittableNullable(value); + + public static void WriteColor32(this NetworkWriter writer, Color32 value) => writer.WriteBlittable(value); + public static void WriteColor32Nullable(this NetworkWriter writer, Color32? value) => writer.WriteBlittableNullable(value); + + public static void WriteQuaternion(this NetworkWriter writer, Quaternion value) => writer.WriteBlittable(value); + public static void WriteQuaternionNullable(this NetworkWriter writer, Quaternion? value) => writer.WriteBlittableNullable(value); + + // Rect is a struct with properties instead of fields + public static void WriteRect(this NetworkWriter writer, Rect value) + { + writer.WriteVector2(value.position); + writer.WriteVector2(value.size); + } + public static void WriteRectNullable(this NetworkWriter writer, Rect? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRect(value.Value); + } + + // Plane is a struct with properties instead of fields + public static void WritePlane(this NetworkWriter writer, Plane value) + { + writer.WriteVector3(value.normal); + writer.WriteFloat(value.distance); + } + public static void WritePlaneNullable(this NetworkWriter writer, Plane? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WritePlane(value.Value); + } + + // Ray is a struct with properties instead of fields + public static void WriteRay(this NetworkWriter writer, Ray value) + { + writer.WriteVector3(value.origin); + writer.WriteVector3(value.direction); + } + public static void WriteRayNullable(this NetworkWriter writer, Ray? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteRay(value.Value); + } + + // LayerMask is a struct with properties instead of fields + public static void WriteLayerMask(this NetworkWriter writer, LayerMask layerMask) + { + // 32 layers as a flags enum, max value of 496, we only need a UShort. + writer.WriteUShort((ushort)layerMask.value); + } + public static void WriteLayerMaskNullable(this NetworkWriter writer, LayerMask? layerMask) + { + writer.WriteBool(layerMask.HasValue); + if (layerMask.HasValue) + writer.WriteLayerMask(layerMask.Value); + } + + public static void WriteMatrix4x4(this NetworkWriter writer, Matrix4x4 value) => writer.WriteBlittable(value); + public static void WriteMatrix4x4Nullable(this NetworkWriter writer, Matrix4x4? value) => writer.WriteBlittableNullable(value); + + public static void WriteGuid(this NetworkWriter writer, Guid value) + { +#if !UNITY_2021_3_OR_NEWER + // Unity 2019 doesn't have Span yet + byte[] data = value.ToByteArray(); + writer.WriteBytes(data, 0, data.Length); +#else + // WriteBlittable(Guid) isn't safe. see WriteBlittable comments. + // Guid is Sequential, but we can't guarantee packing. + // TryWriteBytes is safe and allocation free. + writer.EnsureCapacity(writer.Position + 16); + value.TryWriteBytes(new Span(writer.buffer, writer.Position, 16)); + writer.Position += 16; +#endif + } + public static void WriteGuidNullable(this NetworkWriter writer, Guid? value) + { + writer.WriteBool(value.HasValue); + if (value.HasValue) + writer.WriteGuid(value.Value); + } + + public static void WriteNetworkIdentity(this NetworkWriter writer, NetworkIdentity value) + { + if (value == null) + { + writer.WriteUInt(0); + return; + } + + // users might try to use unspawned / prefab GameObjects in + // rpcs/cmds/syncvars/messages. they would be null on the other + // end, and it might not be obvious why. let's make it obvious. + // https://github.com/vis2k/Mirror/issues/2060 + // + // => warning (instead of exception) because we also use a warning + // if a GameObject doesn't have a NetworkIdentity component etc. + if (value.netId == 0) + Debug.LogWarning($"Attempted to serialize unspawned GameObject: {value.name}. Prefabs and unspawned GameObjects would always be null on the other side. Please spawn it before using it in [SyncVar]s/Rpcs/Cmds/NetworkMessages etc."); + + writer.WriteUInt(value.netId); + } + + public static void WriteNetworkBehaviour(this NetworkWriter writer, NetworkBehaviour value) + { + if (value == null) + { + writer.WriteUInt(0); + return; + } + + // users might try to use unspawned / prefab NetworkBehaviours in + // rpcs/cmds/syncvars/messages. they would be null on the other + // end, and it might not be obvious why. let's make it obvious. + // https://github.com/vis2k/Mirror/issues/2060 + // and more recently https://github.com/MirrorNetworking/Mirror/issues/3399 + // + // => warning (instead of exception) because we also use a warning + // when writing an unspawned NetworkIdentity + if (value.netId == 0) + { + Debug.LogWarning($"Attempted to serialize unspawned NetworkBehaviour: of type {value.GetType()} on GameObject {value.name}. Prefabs and unspawned GameObjects would always be null on the other side. Please spawn it before using it in [SyncVar]s/Rpcs/Cmds/NetworkMessages etc."); + writer.WriteUInt(0); + return; + } + + writer.WriteUInt(value.netId); + writer.WriteByte(value.ComponentIndex); + } + + public static void WriteTransform(this NetworkWriter writer, Transform value) + { + if (value == null) + { + writer.WriteUInt(0); + return; + } + if (value.TryGetComponent(out NetworkIdentity identity)) + { + writer.WriteUInt(identity.netId); + } + else + { + // if users attempt to pass a transform without NetworkIdentity + // to a [Command] or [SyncVar], it should show an obvious warning. + Debug.LogWarning($"Attempted to sync a Transform ({value}) which isn't networked. Transforms without a NetworkIdentity component can't be synced."); + writer.WriteUInt(0); + } + } + + public static void WriteGameObject(this NetworkWriter writer, GameObject value) + { + if (value == null) + { + writer.WriteUInt(0); + return; + } + + // warn if the GameObject doesn't have a NetworkIdentity, + if (!value.TryGetComponent(out NetworkIdentity identity)) + Debug.LogWarning($"Attempted to sync a GameObject ({value}) which isn't networked. GameObject without a NetworkIdentity component can't be synced."); + + // serialize the correct amount of data in any case to make sure + // that the other end can read the expected amount of data too. + writer.WriteNetworkIdentity(identity); + } + + // while SyncList is recommended for NetworkBehaviours, + // structs may have .List members which weaver needs to be able to + // fully serialize for NetworkMessages etc. + // note that Weaver/Writers/GenerateWriter() handles this manually. + public static void WriteList(this NetworkWriter writer, List list) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + if (list is null) + { + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, 0u); + // writer.WriteUInt(0); + return; + } + + // check if within max size, otherwise Reader can't read it. + if (list.Count > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteList - List<{typeof(T)}> too big: {list.Count} elements. Limit: {NetworkReader.AllocationLimit}"); + + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, checked((uint)list.Count) + 1u); + // writer.WriteUInt(checked((uint)list.Count) + 1u); + for (int i = 0; i < list.Count; i++) + writer.Write(list[i]); + } + + // while SyncSet is recommended for NetworkBehaviours, + // structs may have .Set members which weaver needs to be able to + // fully serialize for NetworkMessages etc. + // note that Weaver/Writers/GenerateWriter() handles this manually. + public static void WriteHashSet(this NetworkWriter writer, HashSet hashSet) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + if (hashSet is null) + { + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, 0u); + //writer.WriteUInt(0); + return; + } + + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, checked((uint)hashSet.Count) + 1u); + //writer.WriteUInt(checked((uint)hashSet.Count) + 1u); + foreach (T item in hashSet) + writer.Write(item); + } + + public static void WriteArray(this NetworkWriter writer, T[] array) + { + // we offset count by '1' to easily support null without writing another byte. + // encoding null as '0' instead of '-1' also allows for better compression + // (ushort vs. short / varuint vs. varint) etc. + if (array is null) + { + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, 0u); + // writer.WriteUInt(0); + return; + } + + // check if within max size, otherwise Reader can't read it. + if (array.Length > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteArray - Array<{typeof(T)}> too big: {array.Length} elements. Limit: {NetworkReader.AllocationLimit}"); + + // most sizes are small, write size as VarUInt! + Compression.CompressVarUInt(writer, checked((uint)array.Length) + 1u); + // writer.WriteUInt(checked((uint)array.Length) + 1u); + for (int i = 0; i < array.Length; i++) + writer.Write(array[i]); + } + + public static void WriteUri(this NetworkWriter writer, Uri uri) + { + writer.WriteString(uri?.ToString()); + } + + public static void WriteTexture2D(this NetworkWriter writer, Texture2D texture2D) + { + // TODO allocation protection when sending textures to server. + // currently can allocate 32k x 32k x 4 byte = 3.8 GB + + // support 'null' textures for [SyncVar]s etc. + // https://github.com/vis2k/Mirror/issues/3144 + // simply send -1 for width. + if (texture2D == null) + { + writer.WriteShort(-1); + return; + } + + // check if within max size, otherwise Reader can't read it. + int totalSize = texture2D.width * texture2D.height; + if (totalSize > NetworkReader.AllocationLimit) + throw new IndexOutOfRangeException($"NetworkWriter.WriteTexture2D - Texture2D total size (width*height) too big: {totalSize}. Limit: {NetworkReader.AllocationLimit}"); + + // write dimensions first so reader can create the texture with size + // 32k x 32k short is more than enough + writer.WriteShort((short)texture2D.width); + writer.WriteShort((short)texture2D.height); + writer.WriteArray(texture2D.GetPixels32()); + } + + public static void WriteSprite(this NetworkWriter writer, Sprite sprite) + { + // support 'null' textures for [SyncVar]s etc. + // https://github.com/vis2k/Mirror/issues/3144 + // simply send a 'null' for texture content. + if (sprite == null) + { + writer.WriteTexture2D(null); + return; + } + + writer.WriteTexture2D(sprite.texture); + writer.WriteRect(sprite.rect); + writer.WriteVector2(sprite.pivot); + } + + public static void WriteDateTime(this NetworkWriter writer, DateTime dateTime) + { + writer.WriteDouble(dateTime.ToOADate()); + } + + public static void WriteDateTimeNullable(this NetworkWriter writer, DateTime? dateTime) + { + writer.WriteBool(dateTime.HasValue); + if (dateTime.HasValue) + writer.WriteDouble(dateTime.Value.ToOADate()); + } + } +} diff --git a/Assets/Mirror/Core/NetworkWriterExtensions.cs.meta b/Assets/Mirror/Core/NetworkWriterExtensions.cs.meta new file mode 100644 index 0000000..f0c4e31 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterExtensions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 94259792df2a404892c3e2377f58d0cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkWriterExtensions.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkWriterPool.cs b/Assets/Mirror/Core/NetworkWriterPool.cs new file mode 100644 index 0000000..23f6026 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterPool.cs @@ -0,0 +1,40 @@ +// API consistent with Microsoft's ObjectPool. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + /// Pool of NetworkWriters to avoid allocations. + public static class NetworkWriterPool + { + // reuse Pool + // we still wrap it in NetworkWriterPool.Get/Recycle so we can reset the + // position before reusing. + // this is also more consistent with NetworkReaderPool where we need to + // assign the internal buffer before reusing. + static readonly Pool Pool = new Pool( + () => new NetworkWriterPooled(), + // initial capacity to avoid allocations in the first few frames + // 1000 * 1200 bytes = around 1 MB. + 1000 + ); + + // expose count for testing + public static int Count => Pool.Count; + + /// Get a writer from the pool. Creates new one if pool is empty. + public static NetworkWriterPooled Get() + { + // grab from pool & reset position + NetworkWriterPooled writer = Pool.Get(); + writer.Reset(); + return writer; + } + + /// Return a writer to the pool. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Return(NetworkWriterPooled writer) + { + Pool.Return(writer); + } + } +} diff --git a/Assets/Mirror/Core/NetworkWriterPool.cs.meta b/Assets/Mirror/Core/NetworkWriterPool.cs.meta new file mode 100644 index 0000000..530777c --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3f34b53bea38e4f259eb8dc211e4fdb6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkWriterPool.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/NetworkWriterPooled.cs b/Assets/Mirror/Core/NetworkWriterPooled.cs new file mode 100644 index 0000000..963ce33 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterPooled.cs @@ -0,0 +1,10 @@ +using System; + +namespace Mirror +{ + /// Pooled NetworkWriter, automatically returned to pool when using 'using' + public sealed class NetworkWriterPooled : NetworkWriter, IDisposable + { + public void Dispose() => NetworkWriterPool.Return(this); + } +} diff --git a/Assets/Mirror/Core/NetworkWriterPooled.cs.meta b/Assets/Mirror/Core/NetworkWriterPooled.cs.meta new file mode 100644 index 0000000..cd170b4 --- /dev/null +++ b/Assets/Mirror/Core/NetworkWriterPooled.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a9fab936bf3c4716a452d94ad5ecbebe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/NetworkWriterPooled.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/PortTransport.cs b/Assets/Mirror/Core/PortTransport.cs new file mode 100644 index 0000000..19a7dfd --- /dev/null +++ b/Assets/Mirror/Core/PortTransport.cs @@ -0,0 +1,13 @@ +// convenience interface for transports which use a port. +// useful for cases where someone wants to 'just set the port' independent of +// which transport it is. +// +// note that not all transports have ports, but most do. + +namespace Mirror +{ + public interface PortTransport + { + ushort Port { get; set; } + } +} diff --git a/Assets/Mirror/Core/PortTransport.cs.meta b/Assets/Mirror/Core/PortTransport.cs.meta new file mode 100644 index 0000000..682143b --- /dev/null +++ b/Assets/Mirror/Core/PortTransport.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f7c7c2820d7974cb28c7bfe9aae890a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/PortTransport.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Prediction.meta b/Assets/Mirror/Core/Prediction.meta new file mode 100644 index 0000000..0483f5a --- /dev/null +++ b/Assets/Mirror/Core/Prediction.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e8e801f9c7f4b858d9a6c162e64ca84 +timeCreated: 1694005962 diff --git a/Assets/Mirror/Core/Prediction/Prediction.cs b/Assets/Mirror/Core/Prediction/Prediction.cs new file mode 100644 index 0000000..d669945 --- /dev/null +++ b/Assets/Mirror/Core/Prediction/Prediction.cs @@ -0,0 +1,195 @@ +// standalone, easy to test algorithms for prediction +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror +{ + // prediction may capture Rigidbody3D/2D/etc. state + // have a common interface. + public interface PredictedState + { + double timestamp { get; } + + // use Vector3 for both Rigidbody3D and Rigidbody2D, that's fine + Vector3 position { get; set; } + Vector3 positionDelta { get; set; } + + Quaternion rotation { get; set; } + Quaternion rotationDelta { get; set; } + + Vector3 velocity { get; set; } + Vector3 velocityDelta { get; set; } + + Vector3 angularVelocity { get; set; } + Vector3 angularVelocityDelta { get; set; } + } + + public static class Prediction + { + // get the two states closest to a given timestamp. + // those can be used to interpolate the exact state at that time. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + public static bool Sample( + SortedList history, + double timestamp, // current server time + out T before, + out T after, + out int afterIndex, + out double t) // interpolation factor + { + before = default; + after = default; + t = 0; + afterIndex = -1; + + // can't sample an empty history + // interpolation needs at least two entries. + // can't Lerp(A, A, 1.5). dist(A, A) * 1.5 is always 0. + if (history.Count < 2) { + return false; + } + + // older than oldest + if (timestamp < history.Keys[0]) { + return false; + } + + // iterate through the history + // TODO this needs to be faster than O(N) + // search around that area. + // should be O(1) most of the time, unless sampling was off. + int index = 0; // manually count when iterating. easier than for-int loop. + KeyValuePair prev = new KeyValuePair(); + + // SortedList foreach iteration allocates a LOT. use for-int instead. + // foreach (KeyValuePair entry in history) { + for (int i = 0; i < history.Count; ++i) + { + double key = history.Keys[i]; + T value = history.Values[i]; + + // exact match? + if (timestamp == key) + { + before = value; + after = value; + afterIndex = index; + t = Mathd.InverseLerp(key, key, timestamp); + return true; + } + + // did we check beyond timestamp? then return the previous two. + if (key > timestamp) + { + before = prev.Value; + after = value; + afterIndex = index; + t = Mathd.InverseLerp(prev.Key, key, timestamp); + return true; + } + + // remember the last + prev = new KeyValuePair(key, value); + index += 1; + } + + return false; + } + + // inserts a server state into the client's history. + // readjust the deltas of the states after the inserted one. + // returns the corrected final position. + // => RingBuffer: see prediction_ringbuffer_2 branch, but it's slower! + public static T CorrectHistory( + SortedList history, + int stateHistoryLimit, + T corrected, // corrected state with timestamp + T before, // state in history before the correction + T after, // state in history after the correction + int afterIndex) // index of the 'after' value so we don't need to find it again here + where T: PredictedState + { + // respect the limit + // TODO unit test to check if it respects max size + if (history.Count >= stateHistoryLimit) + { + history.RemoveAt(0); + afterIndex -= 1; // we removed the first value so all indices are off by one now + } + + // PERFORMANCE OPTIMIZATION: avoid O(N) insertion, only readjust all values after. + // the end result is the same since after.delta and after.position are both recalculated. + // it's technically not correct if we were to reconstruct final position from 0..after..end but + // we never do, we only ever iterate from after..end! + // + // insert the corrected state into the history, or overwrite if already exists + // SortedList insertions are O(N)! + // history[corrected.timestamp] = corrected; + // afterIndex += 1; // we inserted the corrected value before the previous index + + // the entry behind the inserted one still has the delta from (before, after). + // we need to correct it to (corrected, after). + // + // for example: + // before: (t=1.0, delta=10, position=10) + // after: (t=3.0, delta=20, position=30) + // + // then we insert: + // corrected: (t=2.5, delta=__, position=25) + // + // previous delta was from t=1.0 to t=3.0 => 2.0 + // inserted delta is from t=2.5 to t=3.0 => 0.5 + // multiplier is 0.5 / 2.0 = 0.25 + // multiply 'after.delta(20)' by 0.25 to get the new 'after.delta(5) + // + // so the new history is: + // before: (t=1.0, delta=10, position=10) + // corrected: (t=2.5, delta=__, position=25) + // after: (t=3.0, delta= 5, position=__) + // + // so when we apply the correction, the new after.position would be: + // corrected.position(25) + after.delta(5) = 30 + // + double previousDeltaTime = after.timestamp - before.timestamp; // 3.0 - 1.0 = 2.0 + double correctedDeltaTime = after.timestamp - corrected.timestamp; // 3.0 - 2.5 = 0.5 + + // fix multiplier becoming NaN if previousDeltaTime is 0: + // double multiplier = correctedDeltaTime / previousDeltaTime; + double multiplier = previousDeltaTime != 0 ? correctedDeltaTime / previousDeltaTime : 0; // 0.5 / 2.0 = 0.25 + + // recalculate 'after.delta' with the multiplier + after.positionDelta = Vector3.Lerp(Vector3.zero, after.positionDelta, (float)multiplier); + after.velocityDelta = Vector3.Lerp(Vector3.zero, after.velocityDelta, (float)multiplier); + after.angularVelocityDelta = Vector3.Lerp(Vector3.zero, after.angularVelocityDelta, (float)multiplier); + // Quaternions always need to be normalized in order to be a valid rotation after operations + after.rotationDelta = Quaternion.Slerp(Quaternion.identity, after.rotationDelta, (float)multiplier).normalized; + + // changes aren't saved until we overwrite them in the history + history[after.timestamp] = after; + + // second step: readjust all absolute values by rewinding client's delta moves on top of it. + T last = corrected; + for (int i = afterIndex; i < history.Count; ++i) + { + double key = history.Keys[i]; + T value = history.Values[i]; + + // correct absolute position based on last + delta. + value.position = last.position + value.positionDelta; + value.velocity = last.velocity + value.velocityDelta; + value.angularVelocity = last.angularVelocity + value.angularVelocityDelta; + // Quaternions always need to be normalized in order to be a valid rotation after operations + value.rotation = (value.rotationDelta * last.rotation).normalized; // quaternions add delta by multiplying in this order + + // save the corrected entry into history. + history[key] = value; + + // save last + last = value; + } + + // third step: return the final recomputed state. + return last; + } + } +} diff --git a/Assets/Mirror/Core/Prediction/Prediction.cs.meta b/Assets/Mirror/Core/Prediction/Prediction.cs.meta new file mode 100644 index 0000000..37e078f --- /dev/null +++ b/Assets/Mirror/Core/Prediction/Prediction.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 216d494d910445ea8a7acc7c889212d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Prediction/Prediction.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/RemoteCalls.cs b/Assets/Mirror/Core/RemoteCalls.cs new file mode 100644 index 0000000..5dbe52f --- /dev/null +++ b/Assets/Mirror/Core/RemoteCalls.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.RemoteCalls +{ + // invoke type for Cmd/Rpc + public enum RemoteCallType { Command, ClientRpc } + + // remote call function delegate + public delegate void RemoteCallDelegate(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection); + + class Invoker + { + // GameObjects might have multiple components of TypeA.CommandA(). + // when invoking, we check if 'TypeA' is an instance of the type. + // the hash itself isn't enough because we wouldn't know which component + // to invoke it on if there are multiple of the same type. + public Type componentType; + public RemoteCallType callType; + public RemoteCallDelegate function; + public bool cmdRequiresAuthority; + + public bool AreEqual(Type componentType, RemoteCallType remoteCallType, RemoteCallDelegate invokeFunction) => + this.componentType == componentType && + this.callType == remoteCallType && + this.function == invokeFunction; + } + + /// Used to help manage remote calls for NetworkBehaviours + public static class RemoteProcedureCalls + { + public const string InvokeRpcPrefix = "InvokeUserCode_"; + + // one lookup for all remote calls. + // allows us to easily add more remote call types without duplicating code. + // note: do not clear those with [RuntimeInitializeOnLoad] + // + // IMPORTANT: cmd/rpc functions are identified via **HASHES**. + // an index would requires half the bandwidth, but introduces issues + // where static constructors are lazily called, so index order isn't + // guaranteed. keep hashes to avoid: + // https://github.com/vis2k/Mirror/pull/3135 + // https://github.com/vis2k/Mirror/issues/3138 + // BUT: 2 byte hash is enough if we check for collisions. that's what we + // do for NetworkMessage as well. + static readonly Dictionary remoteCallDelegates = new Dictionary(); + + static bool CheckIfDelegateExists(Type componentType, RemoteCallType remoteCallType, RemoteCallDelegate func, ushort functionHash) + { + if (remoteCallDelegates.ContainsKey(functionHash)) + { + // something already registered this hash. + // it's okay if it was the same function. + Invoker oldInvoker = remoteCallDelegates[functionHash]; + if (oldInvoker.AreEqual(componentType, remoteCallType, func)) + { + return true; + } + + // otherwise notify user. there is a rare chance of string + // hash collisions. + Debug.LogError($"Function {oldInvoker.componentType}.{oldInvoker.function.GetMethodName()} and {componentType}.{func.GetMethodName()} have the same hash. Please rename one of them. To save bandwidth, we only use 2 bytes for the hash, which has a small chance of collisions."); + } + + return false; + } + + // pass full function name to avoid ClassA.Func & ClassB.Func collisions + internal static ushort RegisterDelegate(Type componentType, string functionFullName, RemoteCallType remoteCallType, RemoteCallDelegate func, bool cmdRequiresAuthority = true) + { + // type+func so Inventory.RpcUse != Equipment.RpcUse + ushort hash = (ushort)(functionFullName.GetStableHashCode() & 0xFFFF); + + if (CheckIfDelegateExists(componentType, remoteCallType, func, hash)) + return hash; + + remoteCallDelegates[hash] = new Invoker + { + callType = remoteCallType, + componentType = componentType, + function = func, + cmdRequiresAuthority = cmdRequiresAuthority + }; + return hash; + } + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + // need to pass componentType to support invoking on GameObjects with + // multiple components of same type with same remote call. + public static void RegisterCommand(Type componentType, string functionFullName, RemoteCallDelegate func, bool requiresAuthority) => + RegisterDelegate(componentType, functionFullName, RemoteCallType.Command, func, requiresAuthority); + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + // need to pass componentType to support invoking on GameObjects with + // multiple components of same type with same remote call. + public static void RegisterRpc(Type componentType, string functionFullName, RemoteCallDelegate func) => + RegisterDelegate(componentType, functionFullName, RemoteCallType.ClientRpc, func); + + // to clean up tests + internal static void RemoveDelegate(ushort hash) => + remoteCallDelegates.Remove(hash); + + internal static bool GetFunctionMethodName(ushort functionHash, out string methodName) + { + if (remoteCallDelegates.TryGetValue(functionHash, out Invoker invoker)) + { + methodName = invoker.function.GetMethodName().Replace(InvokeRpcPrefix, ""); + return true; + } + methodName = ""; + return false; + } + + // note: no need to throw an error if not found. + // an attacker might just try to call a cmd with an rpc's hash etc. + // returning false is enough. + static bool GetInvokerForHash(ushort functionHash, RemoteCallType remoteCallType, out Invoker invoker) => + remoteCallDelegates.TryGetValue(functionHash, out invoker) && + invoker != null && + invoker.callType == remoteCallType; + + // InvokeCmd/Rpc Delegate can all use the same function here + internal static bool Invoke(ushort functionHash, RemoteCallType remoteCallType, NetworkReader reader, NetworkBehaviour component, NetworkConnectionToClient senderConnection = null) + { + // IMPORTANT: we check if the message's componentIndex component is + // actually of the right type. prevents attackers trying + // to invoke remote calls on wrong components. + if (GetInvokerForHash(functionHash, remoteCallType, out Invoker invoker) && + invoker.componentType.IsInstanceOfType(component)) + { + // invoke function on this component + invoker.function(component, reader, senderConnection); + return true; + } + return false; + } + + // check if the command 'requiresAuthority' which is set in the attribute + internal static bool CommandRequiresAuthority(ushort cmdHash) => + GetInvokerForHash(cmdHash, RemoteCallType.Command, out Invoker invoker) && + invoker.cmdRequiresAuthority; + + /// Gets the handler function by hash. Useful for profilers and debuggers. + public static RemoteCallDelegate GetDelegate(ushort functionHash) => + remoteCallDelegates.TryGetValue(functionHash, out Invoker invoker) + ? invoker.function + : null; + } +} + diff --git a/Assets/Mirror/Core/RemoteCalls.cs.meta b/Assets/Mirror/Core/RemoteCalls.cs.meta new file mode 100644 index 0000000..f3f822d --- /dev/null +++ b/Assets/Mirror/Core/RemoteCalls.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d2cdbcbd1e377d6408a91acbec31ba16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/RemoteCalls.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SnapshotInterpolation.meta b/Assets/Mirror/Core/SnapshotInterpolation.meta new file mode 100644 index 0000000..85ac9a9 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4468e736f87964eaebb9d55fc3e132f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs b/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs new file mode 100644 index 0000000..6b8ba8a --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs @@ -0,0 +1,17 @@ +// Snapshot interface so we can reuse it for all kinds of systems. +// for example, NetworkTransform, NetworkRigidbody, CharacterController etc. +// NOTE: we use '' and 'where T : Snapshot' to avoid boxing. +// List would cause allocations through boxing. +namespace Mirror +{ + public interface Snapshot + { + // the remote timestamp (when it was sent by the remote) + double remoteTime { get; set; } + + // the local timestamp (when it was received on our end) + // technically not needed for basic snapshot interpolation. + // only for dynamic buffer time adjustment. + double localTime { get; set; } + } +} diff --git a/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs.meta new file mode 100644 index 0000000..de82446 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 12afea28fdb94154868a0a3b7a9df55b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SnapshotInterpolation/Snapshot.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs new file mode 100644 index 0000000..50339fb --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs @@ -0,0 +1,390 @@ +// snapshot interpolation V2 by mischa +// +// Unity independent to be engine agnostic & easy to test. +// boxing: in C#, uses does not box! passing the interface would box! +// +// credits: +// glenn fiedler: https://gafferongames.com/post/snapshot_interpolation/ +// fholm: netcode streams +// fakebyte: standard deviation for dynamic adjustment +// ninjakicka: math & debugging +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class SortedListExtensions + { + // removes the first 'amount' elements from the sorted list + public static void RemoveRange(this SortedList list, int amount) + { + // remove the first element 'amount' times. + // handles -1 and > count safely. + for (int i = 0; i < amount && i < list.Count; ++i) + list.RemoveAt(0); + } + } + + public static class SnapshotInterpolation + { + // calculate timescale for catch-up / slow-down + // note that negative threshold should be <0. + // caller should verify (i.e. Unity OnValidate). + // improves branch prediction. + public static double Timescale( + double drift, // how far we are off from bufferTime + double catchupSpeed, // in % [0,1] + double slowdownSpeed, // in % [0,1] + double absoluteCatchupNegativeThreshold, // in seconds (careful, we may run out of snapshots) + double absoluteCatchupPositiveThreshold) // in seconds + { + // if the drift time is too large, it means we are behind more time. + // so we need to speed up the timescale. + // note the threshold should be sendInterval * catchupThreshold. + if (drift > absoluteCatchupPositiveThreshold) + { + // localTimeline += 0.001; // too simple, this would ping pong + return 1 + catchupSpeed; // n% faster + } + + // if the drift time is too small, it means we are ahead of time. + // so we need to slow down the timescale. + // note the threshold should be sendInterval * catchupThreshold. + if (drift < absoluteCatchupNegativeThreshold) + { + // localTimeline -= 0.001; // too simple, this would ping pong + return 1 - slowdownSpeed; // n% slower + } + + // keep constant timescale while within threshold. + // this way we have perfectly smooth speed most of the time. + return 1; + } + + // calculate dynamic buffer time adjustment + public static double DynamicAdjustment( + double sendInterval, + double jitterStandardDeviation, + double dynamicAdjustmentTolerance) + { + // jitter is equal to delivery time standard variation. + // delivery time is made up of 'sendInterval+jitter'. + // .Average would be dampened by the constant sendInterval + // .StandardDeviation is the changes in 'jitter' that we want + // so add it to send interval again. + double intervalWithJitter = sendInterval + jitterStandardDeviation; + + // how many multiples of sendInterval is that? + // we want to convert to bufferTimeMultiplier later. + double multiples = intervalWithJitter / sendInterval; + + // add the tolerance + double safezone = multiples + dynamicAdjustmentTolerance; + // UnityEngine.Debug.Log($"sendInterval={sendInterval:F3} jitter std={jitterStandardDeviation:F3} => that is ~{multiples:F1} x sendInterval + {dynamicAdjustmentTolerance} => dynamic bufferTimeMultiplier={safezone}"); + return safezone; + } + + // helper function to insert a snapshot if it doesn't exist yet. + // extra function so we can use it for both cases: + // NetworkClient global timeline insertions & adjustments via Insert. + // NetworkBehaviour local insertion without any time adjustments. + public static bool InsertIfNotExists( + SortedList buffer, // snapshot buffer + int bufferLimit, // don't grow infinitely + T snapshot) // the newly received snapshot + where T : Snapshot + { + // slow clients may not be able to process incoming snapshots fast enough. + // infinitely growing snapshots would make it even worse. + // for example, run NetworkRigidbodyBenchmark while deep profiling client. + // the client just grows and reallocates the buffer forever. + if (buffer.Count >= bufferLimit) return false; + + // SortedList does not allow duplicates. + // we don't need to check ContainsKey (which is expensive). + // simply add and compare count before/after for the return value. + + //if (buffer.ContainsKey(snapshot.remoteTime)) return false; // too expensive + // buffer.Add(snapshot.remoteTime, snapshot); // throws if key exists + + int before = buffer.Count; + buffer[snapshot.remoteTime] = snapshot; // overwrites if key exists + return buffer.Count > before; + } + + // clamp timeline for cases where it gets too far behind. + // for example, a client app may go into the background and get updated + // with 1hz for a while. by the time it's back it's at least 30 frames + // behind, possibly more if the transport also queues up. In this + // scenario, at 1% catch up it took around 20+ seconds to finally catch + // up. For these kinds of scenarios it will be better to snap / clamp. + // + // to reproduce, try snapshot interpolation demo and press the button to + // simulate the client timeline at multiple seconds behind. it'll take + // a long time to catch up if the timeline is a long time behind. + public static double TimelineClamp( + double localTimeline, + double bufferTime, + double latestRemoteTime) + { + // we want local timeline to always be 'bufferTime' behind remote. + double targetTime = latestRemoteTime - bufferTime; + + // we define a boundary of 'bufferTime' around the target time. + // this is where catchup / slowdown will happen. + // outside of the area, we clamp. + double lowerBound = targetTime - bufferTime; // how far behind we can get + double upperBound = targetTime + bufferTime; // how far ahead we can get + return Mathd.Clamp(localTimeline, lowerBound, upperBound); + } + + // call this for every received snapshot. + // adds / inserts it to the list & initializes local time if needed. + public static void InsertAndAdjust( + SortedList buffer, // snapshot buffer + int bufferLimit, // don't grow infinitely + T snapshot, // the newly received snapshot + ref double localTimeline, // local interpolation time based on server time + ref double localTimescale, // timeline multiplier to apply catchup / slowdown over time + float sendInterval, // for debugging + double bufferTime, // offset for buffering + double catchupSpeed, // in % [0,1] + double slowdownSpeed, // in % [0,1] + ref ExponentialMovingAverage driftEma, // for catchup / slowdown + float catchupNegativeThreshold, // in % of sendInteral (careful, we may run out of snapshots) + float catchupPositiveThreshold, // in % of sendInterval + ref ExponentialMovingAverage deliveryTimeEma) // for dynamic buffer time adjustment + where T : Snapshot + { + // first snapshot? + // initialize local timeline. + // we want it to be behind by 'offset'. + // + // note that the first snapshot may be a lagging packet. + // so we would always be behind by that lag. + // this requires catchup later. + if (buffer.Count == 0) + localTimeline = snapshot.remoteTime - bufferTime; + + // insert into the buffer. + // + // note that we might insert it between our current interpolation + // which is fine, it adds another data point for accuracy. + // + // note that insert may be called twice for the same key. + // by default, this would throw. + // need to handle it silently. + if (InsertIfNotExists(buffer, bufferLimit, snapshot)) + { + // dynamic buffer adjustment needs delivery interval jitter + if (buffer.Count >= 2) + { + // note that this is not entirely accurate for scrambled inserts. + // + // we always use the last two, not what we just inserted + // even if we were to use the diff for what we just inserted, + // a scrambled insert would still not be 100% accurate: + // => assume a buffer of AC, with delivery time C-A + // => we then insert B, with delivery time B-A + // => but then technically the first C-A wasn't correct, + // as it would have to be C-B + // + // in practice, scramble is rare and won't make much difference + double previousLocalTime = buffer.Values[buffer.Count - 2].localTime; + double lastestLocalTime = buffer.Values[buffer.Count - 1].localTime; + + // this is the delivery time since last snapshot + double localDeliveryTime = lastestLocalTime - previousLocalTime; + + // feed the local delivery time to the EMA. + // this is what the original stream did too. + // our final dynamic buffer adjustment is different though. + // we use standard deviation instead of average. + deliveryTimeEma.Add(localDeliveryTime); + } + + // adjust timescale to catch up / slow down after each insertion + // because that is when we add new values to our EMA. + + // we want localTimeline to be about 'bufferTime' behind. + // for that, we need the delivery time EMA. + // snapshots may arrive out of order, we can not use last-timeline. + // we need to use the inserted snapshot's time - timeline. + double latestRemoteTime = snapshot.remoteTime; + + // ensure timeline stays within a reasonable bound behind/ahead. + localTimeline = TimelineClamp(localTimeline, bufferTime, latestRemoteTime); + + // calculate timediff after localTimeline override changes + double timeDiff = latestRemoteTime - localTimeline; + + // next, calculate average of a few seconds worth of timediffs. + // this gives smoother results. + // + // to calculate the average, we could simply loop through the + // last 'n' seconds worth of timediffs, but: + // - our buffer may only store a few snapshots (bufferTime) + // - looping through seconds worth of snapshots every time is + // expensive + // + // to solve this, we use an exponential moving average. + // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + // which is basically fancy math to do the same but faster. + // additionally, it allows us to look at more timeDiff values + // than we sould have access to in our buffer :) + driftEma.Add(timeDiff); + + // timescale depends on driftEma. + // driftEma only changes when inserting. + // therefore timescale only needs to be calculated when inserting. + // saves CPU cycles in Update. + + // next up, calculate how far we are currently away from bufferTime + double drift = driftEma.Value - bufferTime; + + // convert relative thresholds to absolute values based on sendInterval + double absoluteNegativeThreshold = sendInterval * catchupNegativeThreshold; + double absolutePositiveThreshold = sendInterval * catchupPositiveThreshold; + + // next, set localTimescale to catchup consistently in Update(). + // we quantize between default/catchup/slowdown, + // this way we have 'default' speed most of the time(!). + // and only catch up / slow down for a little bit occasionally. + // a consistent multiplier would never be exactly 1.0. + localTimescale = Timescale(drift, catchupSpeed, slowdownSpeed, absoluteNegativeThreshold, absolutePositiveThreshold); + + // debug logging + // UnityEngine.Debug.Log($"sendInterval={sendInterval:F3} bufferTime={bufferTime:F3} drift={drift:F3} driftEma={driftEma.Value:F3} timescale={localTimescale:F3} deliveryIntervalEma={deliveryTimeEma.Value:F3}"); + } + } + + // sample snapshot buffer to find the pair around the given time. + // returns indices so we can use it with RemoveRange to clear old snaps. + // make sure to use use buffer.Values[from/to], not buffer[from/to]. + // make sure to only call this is we have > 0 snapshots. + public static void Sample( + SortedList buffer, // snapshot buffer + double localTimeline, // local interpolation time based on server time. this is basically remoteTime-bufferTime. + out int from, // the snapshot <= time + out int to, // the snapshot >= time + out double t) // interpolation factor + where T : Snapshot + { + from = -1; + to = -1; + t = 0; + + // sample from [0,count-1] so we always have two at 'i' and 'i+1'. + for (int i = 0; i < buffer.Count - 1; ++i) + { + // is local time between these two? + T first = buffer.Values[i]; + T second = buffer.Values[i + 1]; + if (localTimeline >= first.remoteTime && + localTimeline <= second.remoteTime) + { + // use these two snapshots + from = i; + to = i + 1; + t = Mathd.InverseLerp(first.remoteTime, second.remoteTime, localTimeline); + return; + } + } + + // didn't find two snapshots around local time. + // so pick either the first or last, depending on which is closer. + + // oldest snapshot ahead of local time? + if (buffer.Values[0].remoteTime > localTimeline) + { + from = to = 0; + t = 0; + } + // otherwise initialize both to the last one + else + { + from = to = buffer.Count - 1; + t = 0; + } + } + + // progress local timeline every update. + // + // ONLY CALL IF SNAPSHOTS.COUNT > 0! + // + // decoupled from Step for easier testing and so we can progress + // time only once in NetworkClient, while stepping for each component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void StepTime( + double deltaTime, // engine delta time (unscaled) + ref double localTimeline, // local interpolation time based on server time + double localTimescale) // catchup / slowdown is applied to time every update) + { + // move local forward in time, scaled with catchup / slowdown applied + localTimeline += deltaTime * localTimescale; + } + + // sample, clear old. + // call this every update. + // + // ONLY CALL IF SNAPSHOTS.COUNT > 0! + // + // returns true if there is anything to apply (requires at least 1 snap) + // from/to/t are out parameters instead of an interpolated 'computed'. + // this allows us to store from/to/t globally (i.e. in NetworkClient) + // and have each component apply the interpolation manually. + // besides, passing "Func Interpolate" would allocate anyway. + public static void StepInterpolation( + SortedList buffer, // snapshot buffer + double localTimeline, // local interpolation time based on server time. this is basically remoteTime-bufferTime. + out T fromSnapshot, // we interpolate 'from' this snapshot + out T toSnapshot, // 'to' this snapshot + out double t) // at ratio 't' [0,1] + where T : Snapshot + { + // check this in caller: + // nothing to do if there are no snapshots at all yet + // if (buffer.Count == 0) return false; + + // sample snapshot buffer at local interpolation time + Sample(buffer, localTimeline, out int from, out int to, out t); + + // save from/to + fromSnapshot = buffer.Values[from]; + toSnapshot = buffer.Values[to]; + + // remove older snapshots that we definitely don't need anymore. + // after(!) using the indices. + // + // if we have 3 snapshots and we are between 2nd and 3rd: + // from = 1, to = 2 + // then we need to remove the first one, which is exactly 'from'. + // because 'from-1' = 0 would remove none. + buffer.RemoveRange(from); + } + + // update time, sample, clear old. + // call this every update. + // + // ONLY CALL IF SNAPSHOTS.COUNT > 0! + // + // returns true if there is anything to apply (requires at least 1 snap) + // from/to/t are out parameters instead of an interpolated 'computed'. + // this allows us to store from/to/t globally (i.e. in NetworkClient) + // and have each component apply the interpolation manually. + // besides, passing "Func Interpolate" would allocate anyway. + public static void Step( + SortedList buffer, // snapshot buffer + double deltaTime, // engine delta time (unscaled) + ref double localTimeline, // local interpolation time based on server time + double localTimescale, // catchup / slowdown is applied to time every update + out T fromSnapshot, // we interpolate 'from' this snapshot + out T toSnapshot, // 'to' this snapshot + out double t) // at ratio 't' [0,1] + where T : Snapshot + { + StepTime(deltaTime, ref localTimeline, localTimescale); + StepInterpolation(buffer, localTimeline, out fromSnapshot, out toSnapshot, out t); + } + } +} diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs.meta new file mode 100644 index 0000000..6cb24d5 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 72c16070d85334011853813488ab1431 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs new file mode 100644 index 0000000..74feae4 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs @@ -0,0 +1,70 @@ +// snapshot interpolation settings struct. +// can easily be exposed in Unity inspectors. +using System; +using UnityEngine; + +namespace Mirror +{ + // class so we can define defaults easily + [Serializable] + public class SnapshotInterpolationSettings + { + // decrease bufferTime at runtime to see the catchup effect. + // increase to see slowdown. + // 'double' so we can have very precise dynamic adjustment without rounding + [Header("Buffering")] + [Tooltip("Local simulation is behind by sendInterval * multiplier seconds.\n\nThis guarantees that we always have enough snapshots in the buffer to mitigate lags & jitter.\n\nIncrease this if the simulation isn't smooth. By default, it should be around 2.")] + public double bufferTimeMultiplier = 2; + + [Tooltip("If a client can't process snapshots fast enough, don't store too many.")] + public int bufferLimit = 32; + + // catchup ///////////////////////////////////////////////////////////// + // catchup thresholds in 'frames'. + // half a frame might be too aggressive. + [Header("Catchup / Slowdown")] + [Tooltip("Slowdown begins when the local timeline is moving too fast towards remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be negative.\n\nDon't modify unless you know what you are doing.")] + public float catchupNegativeThreshold = -1; // careful, don't want to run out of snapshots + + [Tooltip("Catchup begins when the local timeline is moving too slow and getting too far away from remote time. Threshold is in frames worth of snapshots.\n\nThis needs to be positive.\n\nDon't modify unless you know what you are doing.")] + public float catchupPositiveThreshold = 1; + + [Tooltip("Local timeline acceleration in % while catching up.")] + [Range(0, 1)] + public double catchupSpeed = 0.02f; // see snap interp demo. 1% is too slow. + + [Tooltip("Local timeline slowdown in % while slowing down.")] + [Range(0, 1)] + public double slowdownSpeed = 0.04f; // slow down a little faster so we don't encounter empty buffer (= jitter) + + [Tooltip("Catchup/Slowdown is adjusted over n-second exponential moving average.")] + public int driftEmaDuration = 1; // shouldn't need to modify this, but expose it anyway + + // dynamic buffer time adjustment ////////////////////////////////////// + // dynamically adjusts bufferTimeMultiplier for smooth results. + // to understand how this works, try this manually: + // + // - disable dynamic adjustment + // - set jitter = 0.2 (20% is a lot!) + // - notice some stuttering + // - disable interpolation to see just how much jitter this really is(!) + // - enable interpolation again + // - manually increase bufferTimeMultiplier to 3-4 + // ... the cube slows down (blue) until it's smooth + // - with dynamic adjustment enabled, it will set 4 automatically + // ... the cube slows down (blue) until it's smooth as well + // + // note that 20% jitter is extreme. + // for this to be perfectly smooth, set the safety tolerance to '2'. + // but realistically this is not necessary, and '1' is enough. + [Header("Dynamic Adjustment")] + [Tooltip("Automatically adjust bufferTimeMultiplier for smooth results.\nSets a low multiplier on stable connections, and a high multiplier on jittery connections.")] + public bool dynamicAdjustment = true; + + [Tooltip("Safety buffer that is always added to the dynamic bufferTimeMultiplier adjustment.")] + public float dynamicAdjustmentTolerance = 1; // 1 is realistically just fine, 2 is very very safe even for 20% jitter. can be half a frame too. (see above comments) + + [Tooltip("Dynamic adjustment is computed over n-second exponential moving average standard deviation.")] + public int deliveryTimeEmaDuration = 2; // 1-2s recommended to capture average delivery time + } +} diff --git a/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta new file mode 100644 index 0000000..f90b1da --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f955b76b7956417088c03992b3622dc9 +timeCreated: 1678507210 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolationSettings.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs new file mode 100644 index 0000000..5bfdd3a --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs @@ -0,0 +1,15 @@ +namespace Mirror +{ + // empty snapshot that is only used to progress client's local timeline. + public struct TimeSnapshot : Snapshot + { + public double remoteTime { get; set; } + public double localTime { get; set; } + + public TimeSnapshot(double remoteTime, double localTime) + { + this.remoteTime = remoteTime; + this.localTime = localTime; + } + } +} diff --git a/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta new file mode 100644 index 0000000..2215879 --- /dev/null +++ b/Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: afe2b5ed49634971a2aec720ad74e5cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SnapshotInterpolation/TimeSnapshot.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SyncDictionary.cs b/Assets/Mirror/Core/SyncDictionary.cs new file mode 100644 index 0000000..29bc931 --- /dev/null +++ b/Assets/Mirror/Core/SyncDictionary.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Mirror +{ + public class SyncIDictionary : SyncObject, IDictionary, IReadOnlyDictionary + { + /// This is called after the item is added with TKey + public Action OnAdd; + + /// This is called after the item is changed with TKey. TValue is the OLD item + public Action OnSet; + + /// This is called after the item is removed with TKey. TValue is the OLD item + public Action OnRemove; + + /// This is called before the data is cleared + public Action OnClear; + + public enum Operation : byte + { + OP_ADD, + OP_SET, + OP_REMOVE, + OP_CLEAR + } + + /// + /// This is called for all changes to the Dictionary. + /// For OP_ADD, TValue is the NEW value of the entry. + /// For OP_SET and OP_REMOVE, TValue is the OLD value of the entry. + /// For OP_CLEAR, both TKey and TValue are default. + /// + public Action OnChange; + + protected readonly IDictionary objects; + + public SyncIDictionary(IDictionary objects) + { + this.objects = objects; + } + + public int Count => objects.Count; + public bool IsReadOnly => !IsWritable(); + + struct Change + { + internal Operation operation; + internal TKey key; + internal TValue item; + } + + // list of changes. + // -> insert/delete/clear is only ONE change + // -> changing the same slot 10x causes 10 changes. + // -> note that this grows until next sync(!) + // TODO Dictionary to avoid ever growing changes / redundant changes! + readonly List changes = new List(); + + // how many changes we need to ignore + // this is needed because when we initialize the list, + // we might later receive changes that have already been applied + // so we need to skip them + int changesAhead; + + public ICollection Keys => objects.Keys; + + public ICollection Values => objects.Values; + + IEnumerable IReadOnlyDictionary.Keys => objects.Keys; + + IEnumerable IReadOnlyDictionary.Values => objects.Values; + + public override void OnSerializeAll(NetworkWriter writer) + { + // if init, write the full list content + writer.WriteUInt((uint)objects.Count); + + foreach (KeyValuePair syncItem in objects) + { + writer.Write(syncItem.Key); + writer.Write(syncItem.Value); + } + + // all changes have been applied already + // thus the client will need to skip all the pending changes + // or they would be applied again. + // So we write how many changes are pending + writer.WriteUInt((uint)changes.Count); + } + + public override void OnSerializeDelta(NetworkWriter writer) + { + // write all the queued up changes + writer.WriteUInt((uint)changes.Count); + + for (int i = 0; i < changes.Count; i++) + { + Change change = changes[i]; + writer.WriteByte((byte)change.operation); + + switch (change.operation) + { + case Operation.OP_ADD: + case Operation.OP_SET: + writer.Write(change.key); + writer.Write(change.item); + break; + case Operation.OP_REMOVE: + writer.Write(change.key); + break; + case Operation.OP_CLEAR: + break; + } + } + } + + public override void OnDeserializeAll(NetworkReader reader) + { + // if init, write the full list content + int count = (int)reader.ReadUInt(); + + objects.Clear(); + changes.Clear(); + + for (int i = 0; i < count; i++) + { + TKey key = reader.Read(); + TValue obj = reader.Read(); + objects.Add(key, obj); + } + + // We will need to skip all these changes + // the next time the list is synchronized + // because they have already been applied + changesAhead = (int)reader.ReadUInt(); + } + + public override void OnDeserializeDelta(NetworkReader reader) + { + int changesCount = (int)reader.ReadUInt(); + + for (int i = 0; i < changesCount; i++) + { + Operation operation = (Operation)reader.ReadByte(); + + // apply the operation only if it is a new change + // that we have not applied yet + bool apply = changesAhead == 0; + TKey key = default; + TValue item = default; + + switch (operation) + { + case Operation.OP_ADD: + case Operation.OP_SET: + key = reader.Read(); + item = reader.Read(); + if (apply) + { + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + if (objects.TryGetValue(key, out TValue oldItem)) + { + objects[key] = item; // assign after TryGetValue + AddOperation(Operation.OP_SET, key, item, oldItem, false); + } + else + { + objects[key] = item; // assign after TryGetValue + AddOperation(Operation.OP_ADD, key, item, default, false); + } + } + break; + + case Operation.OP_CLEAR: + if (apply) + { + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_CLEAR, default, default, default, false); + // clear after invoking the callback so users can iterate the dictionary + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + break; + + case Operation.OP_REMOVE: + key = reader.Read(); + if (apply) + { + if (objects.TryGetValue(key, out TValue oldItem)) + { + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + objects.Remove(key); + AddOperation(Operation.OP_REMOVE, key, oldItem, oldItem, false); + } + } + break; + } + + if (!apply) + { + // we just skipped this change + changesAhead--; + } + } + } + + // throw away all the changes + // this should be called after a successful sync + public override void ClearChanges() => changes.Clear(); + + public override void Reset() + { + changes.Clear(); + changesAhead = 0; + objects.Clear(); + } + + public TValue this[TKey i] + { + get => objects[i]; + set + { + if (ContainsKey(i)) + { + TValue oldItem = objects[i]; + objects[i] = value; + AddOperation(Operation.OP_SET, i, value, oldItem, true); + } + else + { + objects[i] = value; + AddOperation(Operation.OP_ADD, i, value, default, true); + } + } + } + + public bool TryGetValue(TKey key, out TValue value) => objects.TryGetValue(key, out value); + + public bool ContainsKey(TKey key) => objects.ContainsKey(key); + + public bool Contains(KeyValuePair item) => TryGetValue(item.Key, out TValue val) && EqualityComparer.Default.Equals(val, item.Value); + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (arrayIndex < 0 || arrayIndex > array.Length) + throw new System.ArgumentOutOfRangeException(nameof(arrayIndex), "Array Index Out of Range"); + + if (array.Length - arrayIndex < Count) + throw new System.ArgumentException("The number of items in the SyncDictionary is greater than the available space from arrayIndex to the end of the destination array"); + + int i = arrayIndex; + foreach (KeyValuePair item in objects) + { + array[i] = item; + i++; + } + } + + public void Add(KeyValuePair item) => Add(item.Key, item.Value); + + public void Add(TKey key, TValue value) + { + objects.Add(key, value); + AddOperation(Operation.OP_ADD, key, value, default, true); + } + + public bool Remove(TKey key) + { + if (objects.TryGetValue(key, out TValue oldItem) && objects.Remove(key)) + { + AddOperation(Operation.OP_REMOVE, key, oldItem, oldItem, true); + return true; + } + return false; + } + + public bool Remove(KeyValuePair item) + { + bool result = objects.Remove(item.Key); + if (result) + AddOperation(Operation.OP_REMOVE, item.Key, item.Value, item.Value, true); + + return result; + } + + public void Clear() + { + AddOperation(Operation.OP_CLEAR, default, default, default, true); + // clear after invoking the callback so users can iterate the dictionary + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + + void AddOperation(Operation op, TKey key, TValue item, TValue oldItem, bool checkAccess) + { + if (checkAccess && IsReadOnly) + throw new InvalidOperationException("SyncDictionaries can only be modified by the owner."); + + Change change = new Change + { + operation = op, + key = key, + item = item + }; + + if (IsRecording()) + { + changes.Add(change); + OnDirty?.Invoke(); + } + + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(key); + OnChange?.Invoke(op, key, item); + break; + case Operation.OP_SET: + OnSet?.Invoke(key, oldItem); + OnChange?.Invoke(op, key, oldItem); + break; + case Operation.OP_REMOVE: + OnRemove?.Invoke(key, oldItem); + OnChange?.Invoke(op, key, oldItem); + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, default, default); + break; + } + } + + public IEnumerator> GetEnumerator() => objects.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => objects.GetEnumerator(); + } + + public class SyncDictionary : SyncIDictionary + { + public SyncDictionary() : base(new Dictionary()) { } + public SyncDictionary(IEqualityComparer eq) : base(new Dictionary(eq)) { } + public SyncDictionary(IDictionary d) : base(new Dictionary(d)) { } + public new Dictionary.ValueCollection Values => ((Dictionary)objects).Values; + public new Dictionary.KeyCollection Keys => ((Dictionary)objects).Keys; + public new Dictionary.Enumerator GetEnumerator() => ((Dictionary)objects).GetEnumerator(); + } +} diff --git a/Assets/Mirror/Core/SyncDictionary.cs.meta b/Assets/Mirror/Core/SyncDictionary.cs.meta new file mode 100644 index 0000000..d9362fe --- /dev/null +++ b/Assets/Mirror/Core/SyncDictionary.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4b346c49cfdb668488a364c3023590e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SyncDictionary.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SyncList.cs b/Assets/Mirror/Core/SyncList.cs new file mode 100644 index 0000000..3986725 --- /dev/null +++ b/Assets/Mirror/Core/SyncList.cs @@ -0,0 +1,473 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Mirror +{ + public class SyncList : SyncObject, IList, IReadOnlyList + { + /// This is called after the item is added with index + public Action OnAdd; + + /// This is called after the item is inserted with index + public Action OnInsert; + + /// This is called after the item is set with index and OLD Value + public Action OnSet; + + /// This is called after the item is removed with index and OLD Value + public Action OnRemove; + + /// This is called before the list is cleared so the list can be iterated + public Action OnClear; + + public enum Operation : byte + { + OP_ADD, + OP_SET, + OP_INSERT, + OP_REMOVEAT, + OP_CLEAR + } + + /// + /// This is called for all changes to the List. + /// For OP_ADD and OP_INSERT, T is the NEW value of the entry. + /// For OP_SET and OP_REMOVE, T is the OLD value of the entry. + /// For OP_CLEAR, T is default. + /// + // TODO deprecate in favor of explicit Callback, later rename Callback to OnChange for consistency with other SyncCollections. + public Action OnChange; + + /// + /// This is called for all changes to the List. + /// Parameters: Operation, index, oldItem, newItem. + /// Sometimes we need both oldItem and newItem. + /// Keep for compatibility since 10 years of projects use this. + /// + public Action Callback; + + readonly IList objects; + readonly IEqualityComparer comparer; + + public int Count => objects.Count; + public bool IsReadOnly => !IsWritable(); + + struct Change + { + internal Operation operation; + internal int index; + internal T item; + } + + // list of changes. + // -> insert/delete/clear is only ONE change + // -> changing the same slot 10x caues 10 changes. + // -> note that this grows until next sync(!) + readonly List changes = new List(); + + // how many changes we need to ignore + // this is needed because when we initialize the list, + // we might later receive changes that have already been applied + // so we need to skip them + int changesAhead; + + public SyncList() : this(EqualityComparer.Default) { } + + public SyncList(IEqualityComparer comparer) + { + this.comparer = comparer ?? EqualityComparer.Default; + objects = new List(); + } + + public SyncList(IList objects, IEqualityComparer comparer = null) + { + this.comparer = comparer ?? EqualityComparer.Default; + this.objects = objects; + } + + // throw away all the changes + // this should be called after a successful sync + public override void ClearChanges() => changes.Clear(); + + public override void Reset() + { + changes.Clear(); + changesAhead = 0; + objects.Clear(); + } + + void AddOperation(Operation op, int itemIndex, T oldItem, T newItem, bool checkAccess) + { + if (checkAccess && IsReadOnly) + throw new InvalidOperationException("Synclists can only be modified by the owner."); + + Change change = new Change + { + operation = op, + index = itemIndex, + item = newItem + }; + + if (IsRecording()) + { + changes.Add(change); + OnDirty?.Invoke(); + } + + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(itemIndex); + OnChange?.Invoke(op, itemIndex, newItem); + Callback?.Invoke(op, itemIndex, oldItem, newItem); + break; + case Operation.OP_INSERT: + OnInsert?.Invoke(itemIndex); + OnChange?.Invoke(op, itemIndex, newItem); + Callback?.Invoke(op, itemIndex, oldItem, newItem); + break; + case Operation.OP_SET: + OnSet?.Invoke(itemIndex, oldItem); + OnChange?.Invoke(op, itemIndex, oldItem); + Callback?.Invoke(op, itemIndex, oldItem, newItem); + break; + case Operation.OP_REMOVEAT: + OnRemove?.Invoke(itemIndex, oldItem); + OnChange?.Invoke(op, itemIndex, oldItem); + Callback?.Invoke(op, itemIndex, oldItem, newItem); + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, itemIndex, default); + Callback?.Invoke(op, itemIndex, default, default); + break; + } + } + + public override void OnSerializeAll(NetworkWriter writer) + { + // if init, write the full list content + writer.WriteUInt((uint)objects.Count); + + for (int i = 0; i < objects.Count; i++) + { + T obj = objects[i]; + writer.Write(obj); + } + + // all changes have been applied already + // thus the client will need to skip all the pending changes + // or they would be applied again. + // So we write how many changes are pending + writer.WriteUInt((uint)changes.Count); + } + + public override void OnSerializeDelta(NetworkWriter writer) + { + // write all the queued up changes + writer.WriteUInt((uint)changes.Count); + + for (int i = 0; i < changes.Count; i++) + { + Change change = changes[i]; + writer.WriteByte((byte)change.operation); + + switch (change.operation) + { + case Operation.OP_ADD: + writer.Write(change.item); + break; + + case Operation.OP_CLEAR: + break; + + case Operation.OP_REMOVEAT: + writer.WriteUInt((uint)change.index); + break; + + case Operation.OP_INSERT: + case Operation.OP_SET: + writer.WriteUInt((uint)change.index); + writer.Write(change.item); + break; + } + } + } + + public override void OnDeserializeAll(NetworkReader reader) + { + // if init, write the full list content + int count = (int)reader.ReadUInt(); + + objects.Clear(); + changes.Clear(); + + for (int i = 0; i < count; i++) + { + T obj = reader.Read(); + objects.Add(obj); + } + + // We will need to skip all these changes + // the next time the list is synchronized + // because they have already been applied + changesAhead = (int)reader.ReadUInt(); + } + + public override void OnDeserializeDelta(NetworkReader reader) + { + int changesCount = (int)reader.ReadUInt(); + + for (int i = 0; i < changesCount; i++) + { + Operation operation = (Operation)reader.ReadByte(); + + // apply the operation only if it is a new change + // that we have not applied yet + bool apply = changesAhead == 0; + int index = 0; + T oldItem = default; + T newItem = default; + + switch (operation) + { + case Operation.OP_ADD: + newItem = reader.Read(); + if (apply) + { + index = objects.Count; + objects.Add(newItem); + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_ADD, objects.Count - 1, default, newItem, false); + } + break; + + case Operation.OP_CLEAR: + if (apply) + { + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_CLEAR, 0, default, default, false); + // clear after invoking the callback so users can iterate the list + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + break; + + case Operation.OP_INSERT: + index = (int)reader.ReadUInt(); + newItem = reader.Read(); + if (apply) + { + objects.Insert(index, newItem); + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_INSERT, index, default, newItem, false); + } + break; + + case Operation.OP_REMOVEAT: + index = (int)reader.ReadUInt(); + if (apply) + { + oldItem = objects[index]; + objects.RemoveAt(index); + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_REMOVEAT, index, oldItem, default, false); + } + break; + + case Operation.OP_SET: + index = (int)reader.ReadUInt(); + newItem = reader.Read(); + if (apply) + { + oldItem = objects[index]; + objects[index] = newItem; + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_SET, index, oldItem, newItem, false); + } + break; + } + + if (!apply) + { + // we just skipped this change + changesAhead--; + } + } + } + + public void Add(T item) + { + objects.Add(item); + AddOperation(Operation.OP_ADD, objects.Count - 1, default, item, true); + } + + public void AddRange(IEnumerable range) + { + foreach (T entry in range) + Add(entry); + } + + public void Clear() + { + AddOperation(Operation.OP_CLEAR, 0, default, default, true); + // clear after invoking the callback so users can iterate the list + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + + public bool Contains(T item) => IndexOf(item) >= 0; + + public void CopyTo(T[] array, int index) => objects.CopyTo(array, index); + + public int IndexOf(T item) + { + for (int i = 0; i < objects.Count; ++i) + if (comparer.Equals(item, objects[i])) + return i; + return -1; + } + + public int FindIndex(Predicate match) + { + for (int i = 0; i < objects.Count; ++i) + if (match(objects[i])) + return i; + return -1; + } + + public T Find(Predicate match) + { + int i = FindIndex(match); + return (i != -1) ? objects[i] : default; + } + + public List FindAll(Predicate match) + { + List results = new List(); + for (int i = 0; i < objects.Count; ++i) + if (match(objects[i])) + results.Add(objects[i]); + return results; + } + + public void Insert(int index, T item) + { + objects.Insert(index, item); + AddOperation(Operation.OP_INSERT, index, default, item, true); + } + + public void InsertRange(int index, IEnumerable range) + { + foreach (T entry in range) + { + Insert(index, entry); + index++; + } + } + + public bool Remove(T item) + { + int index = IndexOf(item); + bool result = index >= 0; + if (result) + RemoveAt(index); + + return result; + } + + public void RemoveAt(int index) + { + T oldItem = objects[index]; + objects.RemoveAt(index); + AddOperation(Operation.OP_REMOVEAT, index, oldItem, default, true); + } + + public int RemoveAll(Predicate match) + { + List toRemove = new List(); + for (int i = 0; i < objects.Count; ++i) + if (match(objects[i])) + toRemove.Add(objects[i]); + + foreach (T entry in toRemove) + Remove(entry); + + return toRemove.Count; + } + + public T this[int i] + { + get => objects[i]; + set + { + if (!comparer.Equals(objects[i], value)) + { + T oldItem = objects[i]; + objects[i] = value; + AddOperation(Operation.OP_SET, i, oldItem, value, true); + } + } + } + + public Enumerator GetEnumerator() => new Enumerator(this); + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); + + // default Enumerator allocates. we need a custom struct Enumerator to + // not allocate on the heap. + // (System.Collections.Generic.List source code does the same) + // + // benchmark: + // uMMORPG with 800 monsters, Skills.GetHealthBonus() which runs a + // foreach on skills SyncList: + // before: 81.2KB GC per frame + // after: 0KB GC per frame + // => this is extremely important for MMO scale networking + public struct Enumerator : IEnumerator + { + readonly SyncList list; + int index; + + public T Current { get; private set; } + + public Enumerator(SyncList list) + { + this.list = list; + index = -1; + Current = default; + } + + public bool MoveNext() + { + if (++index >= list.Count) + return false; + + Current = list[index]; + return true; + } + + public void Reset() => index = -1; + object IEnumerator.Current => Current; + public void Dispose() { } + } + } +} diff --git a/Assets/Mirror/Core/SyncList.cs.meta b/Assets/Mirror/Core/SyncList.cs.meta new file mode 100644 index 0000000..2a1d886 --- /dev/null +++ b/Assets/Mirror/Core/SyncList.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 744fc71f748fe40d5940e04bf42b29f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SyncList.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SyncObject.cs b/Assets/Mirror/Core/SyncObject.cs new file mode 100644 index 0000000..405e240 --- /dev/null +++ b/Assets/Mirror/Core/SyncObject.cs @@ -0,0 +1,53 @@ +using System; + +namespace Mirror +{ + /// SyncObjects sync state between server and client. E.g. SyncLists. + // SyncObject should be a class (instead of an interface) for a few reasons: + // * NetworkBehaviour stores SyncObjects in a list. structs would be a copy + // and OnSerialize would use the copy instead of the original struct. + // * Obsolete functions like Flush() don't need to be defined by each type + // * OnDirty/IsRecording etc. default functions can be defined once here + // for example, handling 'OnDirty wasn't initialized' with a default + // function that throws an exception will be useful for SyncVar + public abstract class SyncObject + { + /// Used internally to set owner NetworkBehaviour's dirty mask bit when changed. + public Action OnDirty; + + /// Used internally to check if we are currently tracking changes. + // prevents ever growing .changes lists: + // if a monster has no observers but we keep modifying a SyncObject, + // then the changes would never be flushed and keep growing, + // because OnSerialize isn't called without observers. + // => Func so we can set it to () => observers.Count > 0 + // without depending on NetworkComponent/NetworkIdentity here. + // => virtual so it simply always records by default + public Func IsRecording = () => true; + + // SyncList/Set/etc. shouldn't be modifiable if not owned. + // otherwise they would silently get out of sync. + // need a lambda because InitSyncObject is called in ctor, when + // 'isClient' etc. aren't initialized yet. + public Func IsWritable = () => true; + + /// Discard all the queued changes + // Consider the object fully synchronized with clients + public abstract void ClearChanges(); + + /// Write a full copy of the object + public abstract void OnSerializeAll(NetworkWriter writer); + + /// Write the changes made to the object since last sync + public abstract void OnSerializeDelta(NetworkWriter writer); + + /// Reads a full copy of the object + public abstract void OnDeserializeAll(NetworkReader reader); + + /// Reads the changes made to the object since last sync + public abstract void OnDeserializeDelta(NetworkReader reader); + + /// Resets the SyncObject so that it can be re-used + public abstract void Reset(); + } +} diff --git a/Assets/Mirror/Core/SyncObject.cs.meta b/Assets/Mirror/Core/SyncObject.cs.meta new file mode 100644 index 0000000..1b78301 --- /dev/null +++ b/Assets/Mirror/Core/SyncObject.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ae226d17a0c844041aa24cc2c023dd49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SyncObject.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/SyncSet.cs b/Assets/Mirror/Core/SyncSet.cs new file mode 100644 index 0000000..7e9fee7 --- /dev/null +++ b/Assets/Mirror/Core/SyncSet.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Mirror +{ + public class SyncSet : SyncObject, ISet + { + /// This is called after the item is added. T is the new item. + public Action OnAdd; + + /// This is called after the item is removed. T is the OLD item + public Action OnRemove; + + /// This is called BEFORE the data is cleared + public Action OnClear; + + public enum Operation : byte + { + OP_ADD, + OP_REMOVE, + OP_CLEAR + } + + /// + /// This is called for all changes to the Set. + /// For OP_ADD, T is the NEW value of the entry. + /// For OP_REMOVE, T is the OLD value of the entry. + /// For OP_CLEAR, T is default. + /// + public Action OnChange; + + protected readonly ISet objects; + + public int Count => objects.Count; + public bool IsReadOnly => !IsWritable(); + + struct Change + { + internal Operation operation; + internal T item; + } + + // list of changes. + // -> insert/delete/clear is only ONE change + // -> changing the same slot 10x caues 10 changes. + // -> note that this grows until next sync(!) + // TODO Dictionary to avoid ever growing changes / redundant changes! + readonly List changes = new List(); + + // how many changes we need to ignore + // this is needed because when we initialize the list, + // we might later receive changes that have already been applied + // so we need to skip them + int changesAhead; + + public SyncSet(ISet objects) + { + this.objects = objects; + } + + public override void Reset() + { + changes.Clear(); + changesAhead = 0; + objects.Clear(); + } + + // throw away all the changes + // this should be called after a successful sync + public override void ClearChanges() => changes.Clear(); + + void AddOperation(Operation op, T oldItem, T newItem, bool checkAccess) + { + if (checkAccess && IsReadOnly) + throw new InvalidOperationException("SyncSets can only be modified by the owner."); + + Change change = default; + switch (op) + { + case Operation.OP_ADD: + change = new Change + { + operation = op, + item = newItem + }; + break; + case Operation.OP_REMOVE: + change = new Change + { + operation = op, + item = oldItem + }; + break; + case Operation.OP_CLEAR: + change = new Change + { + operation = op, + item = default + }; + break; + } + + if (IsRecording()) + { + changes.Add(change); + OnDirty?.Invoke(); + } + + switch (op) + { + case Operation.OP_ADD: + OnAdd?.Invoke(newItem); + OnChange?.Invoke(op, newItem); + break; + case Operation.OP_REMOVE: + OnRemove?.Invoke(oldItem); + OnChange?.Invoke(op, oldItem); + break; + case Operation.OP_CLEAR: + OnClear?.Invoke(); + OnChange?.Invoke(op, default); + break; + } + } + + void AddOperation(Operation op, bool checkAccess) => AddOperation(op, default, default, checkAccess); + + public override void OnSerializeAll(NetworkWriter writer) + { + // if init, write the full list content + writer.WriteUInt((uint)objects.Count); + + foreach (T obj in objects) + writer.Write(obj); + + // all changes have been applied already + // thus the client will need to skip all the pending changes + // or they would be applied again. + // So we write how many changes are pending + writer.WriteUInt((uint)changes.Count); + } + + public override void OnSerializeDelta(NetworkWriter writer) + { + // write all the queued up changes + writer.WriteUInt((uint)changes.Count); + + for (int i = 0; i < changes.Count; i++) + { + Change change = changes[i]; + writer.WriteByte((byte)change.operation); + + switch (change.operation) + { + case Operation.OP_ADD: + writer.Write(change.item); + break; + case Operation.OP_REMOVE: + writer.Write(change.item); + break; + case Operation.OP_CLEAR: + break; + } + } + } + + public override void OnDeserializeAll(NetworkReader reader) + { + // if init, write the full list content + int count = (int)reader.ReadUInt(); + + objects.Clear(); + changes.Clear(); + + for (int i = 0; i < count; i++) + { + T obj = reader.Read(); + objects.Add(obj); + } + + // We will need to skip all these changes + // the next time the list is synchronized + // because they have already been applied + changesAhead = (int)reader.ReadUInt(); + } + + public override void OnDeserializeDelta(NetworkReader reader) + { + int changesCount = (int)reader.ReadUInt(); + + for (int i = 0; i < changesCount; i++) + { + Operation operation = (Operation)reader.ReadByte(); + + // apply the operation only if it is a new change + // that we have not applied yet + bool apply = changesAhead == 0; + T oldItem = default; + T newItem = default; + + switch (operation) + { + case Operation.OP_ADD: + newItem = reader.Read(); + if (apply) + { + objects.Add(newItem); + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_ADD, default, newItem, false); + } + break; + + case Operation.OP_REMOVE: + oldItem = reader.Read(); + if (apply) + { + objects.Remove(oldItem); + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_REMOVE, oldItem, default, false); + } + break; + + case Operation.OP_CLEAR: + if (apply) + { + // add dirty + changes. + // ClientToServer needs to set dirty in server OnDeserialize. + // no access check: server OnDeserialize can always + // write, even for ClientToServer (for broadcasting). + AddOperation(Operation.OP_CLEAR, false); + // clear after invoking the callback so users can iterate the set + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + break; + } + + if (!apply) + { + // we just skipped this change + changesAhead--; + } + } + } + + public bool Add(T item) + { + if (objects.Add(item)) + { + AddOperation(Operation.OP_ADD, default, item, true); + return true; + } + return false; + } + + void ICollection.Add(T item) + { + if (objects.Add(item)) + AddOperation(Operation.OP_ADD, default, item, true); + } + + public void Clear() + { + AddOperation(Operation.OP_CLEAR, true); + // clear after invoking the callback so users can iterate the set + // and take appropriate action on the items before they are wiped. + objects.Clear(); + } + + public bool Contains(T item) => objects.Contains(item); + + public void CopyTo(T[] array, int index) => objects.CopyTo(array, index); + + public bool Remove(T item) + { + if (objects.Remove(item)) + { + AddOperation(Operation.OP_REMOVE, item, default, true); + return true; + } + return false; + } + + public IEnumerator GetEnumerator() => objects.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public void ExceptWith(IEnumerable other) + { + if (other == this) + { + Clear(); + return; + } + + // remove every element in other from this + foreach (T element in other) + Remove(element); + } + + public void IntersectWith(IEnumerable other) + { + if (other is ISet otherSet) + IntersectWithSet(otherSet); + else + { + HashSet otherAsSet = new HashSet(other); + IntersectWithSet(otherAsSet); + } + } + + void IntersectWithSet(ISet otherSet) + { + List elements = new List(objects); + + foreach (T element in elements) + if (!otherSet.Contains(element)) + Remove(element); + } + + public bool IsProperSubsetOf(IEnumerable other) => objects.IsProperSubsetOf(other); + + public bool IsProperSupersetOf(IEnumerable other) => objects.IsProperSupersetOf(other); + + public bool IsSubsetOf(IEnumerable other) => objects.IsSubsetOf(other); + + public bool IsSupersetOf(IEnumerable other) => objects.IsSupersetOf(other); + + public bool Overlaps(IEnumerable other) => objects.Overlaps(other); + + public bool SetEquals(IEnumerable other) => objects.SetEquals(other); + + // custom implementation so we can do our own Clear/Add/Remove for delta + public void SymmetricExceptWith(IEnumerable other) + { + if (other == this) + Clear(); + else + foreach (T element in other) + if (!Remove(element)) + Add(element); + } + + // custom implementation so we can do our own Clear/Add/Remove for delta + public void UnionWith(IEnumerable other) + { + if (other != this) + foreach (T element in other) + Add(element); + } + } + + public class SyncHashSet : SyncSet + { + public SyncHashSet() : this(EqualityComparer.Default) { } + public SyncHashSet(IEqualityComparer comparer) : base(new HashSet(comparer ?? EqualityComparer.Default)) { } + + // allocation free enumerator + public new HashSet.Enumerator GetEnumerator() => ((HashSet)objects).GetEnumerator(); + } + + public class SyncSortedSet : SyncSet + { + public SyncSortedSet() : this(Comparer.Default) { } + public SyncSortedSet(IComparer comparer) : base(new SortedSet(comparer ?? Comparer.Default)) { } + + // allocation free enumerator + public new SortedSet.Enumerator GetEnumerator() => ((SortedSet)objects).GetEnumerator(); + } +} diff --git a/Assets/Mirror/Core/SyncSet.cs.meta b/Assets/Mirror/Core/SyncSet.cs.meta new file mode 100644 index 0000000..8eb0efe --- /dev/null +++ b/Assets/Mirror/Core/SyncSet.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a31599d9f9dd4ef9999f7b9707c832c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/SyncSet.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Threading.meta b/Assets/Mirror/Core/Threading.meta new file mode 100644 index 0000000..037993e --- /dev/null +++ b/Assets/Mirror/Core/Threading.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 752fcafbee1ec45c9a43c0cf65da39de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs new file mode 100644 index 0000000..c0bc926 --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs @@ -0,0 +1,45 @@ +// API consistent with Microsoft's ObjectPool. +// thread safe. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class ConcurrentNetworkWriterPool + { + // initial capacity to avoid allocations in the first few frames + // 1000 * 1200 bytes = around 1 MB. + public const int InitialCapacity = 1000; + + + // reuse ConcurrentPool + // we still wrap it in NetworkWriterPool.Get/Recycle so we can reset the + // position before reusing. + // this is also more consistent with NetworkReaderPool where we need to + // assign the internal buffer before reusing. + static readonly ConcurrentPool pool = + new ConcurrentPool( + // new object function + () => new ConcurrentNetworkWriterPooled(), + // initial capacity to avoid allocations in the first few frames + // 1000 * 1200 bytes = around 1 MB. + InitialCapacity + ); + + // pool size access for debugging & tests + public static int Count => pool.Count; + + public static ConcurrentNetworkWriterPooled Get() + { + // grab from pool & reset position + ConcurrentNetworkWriterPooled writer = pool.Get(); + writer.Position = 0; + return writer; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Return(ConcurrentNetworkWriterPooled writer) + { + pool.Return(writer); + } + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta new file mode 100644 index 0000000..8ff2757 --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: fdf46e334f52400c854c9732f6fcf005 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPool.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs new file mode 100644 index 0000000..4baa7df --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs @@ -0,0 +1,10 @@ +using System; + +namespace Mirror +{ + /// Pooled (not threadsafe) NetworkWriter used from Concurrent pool (thread safe). Automatically returned to concurrent pool when using 'using' + public sealed class ConcurrentNetworkWriterPooled : NetworkWriter, IDisposable + { + public void Dispose() => ConcurrentNetworkWriterPool.Return(this); + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta new file mode 100644 index 0000000..8a1e745 --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9163d963b36b4e389318f312bfd8e488 +timeCreated: 1691485295 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Threading/ConcurrentNetworkWriterPooled.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Threading/ConcurrentPool.cs b/Assets/Mirror/Core/Threading/ConcurrentPool.cs new file mode 100644 index 0000000..eeac0cc --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentPool.cs @@ -0,0 +1,44 @@ +// Pool to avoid allocations (from libuv2k) +// API consistent with Microsoft's ObjectPool. +// concurrent for thread safe access. +// +// currently not in use. keep it in case we need it again. +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public class ConcurrentPool + { + // Mirror is single threaded, no need for concurrent collections + // concurrent bag is for items who's order doesn't matter. + // just about right for our use case here. + readonly ConcurrentBag objects = new ConcurrentBag(); + + // some types might need additional parameters in their constructor, so + // we use a Func generator + readonly Func objectGenerator; + + public ConcurrentPool(Func objectGenerator, int initialCapacity) + { + this.objectGenerator = objectGenerator; + + // allocate an initial pool so we have fewer (if any) + // allocations in the first few frames (or seconds). + for (int i = 0; i < initialCapacity; ++i) + objects.Add(objectGenerator()); + } + + // take an element from the pool, or create a new one if empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Get() => objects.TryTake(out T obj) ? obj : objectGenerator(); + + // return an element to the pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(T item) => objects.Add(item); + + // count to see how many objects are in the pool. useful for tests. + public int Count => objects.Count; + } +} diff --git a/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta b/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta new file mode 100644 index 0000000..cb36abf --- /dev/null +++ b/Assets/Mirror/Core/Threading/ConcurrentPool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ed304bd790ff478ca37233f66d04d1c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Threading/ConcurrentPool.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Threading/ThreadLog.cs b/Assets/Mirror/Core/Threading/ThreadLog.cs new file mode 100644 index 0000000..36dca5f --- /dev/null +++ b/Assets/Mirror/Core/Threading/ThreadLog.cs @@ -0,0 +1,112 @@ +// threaded Debug.Log support (mischa 2022) +// +// Editor shows Debug.Logs from different threads. +// Builds don't show Debug.Logs from different threads. +// +// need to hook into logMessageReceivedThreaded to receive them in builds too. +using System.Collections.Concurrent; +using System.Threading; +using UnityEngine; + +namespace Mirror +{ + public static class ThreadLog + { + // queue log messages from threads + struct LogEntry + { + public int threadId; + public LogType type; + public string message; + public string stackTrace; + + public LogEntry(int threadId, LogType type, string message, string stackTrace) + { + this.threadId = threadId; + this.type = type; + this.message = message; + this.stackTrace = stackTrace; + } + } + + // ConcurrentQueue allocations are fine here. + // logs allocate anywway. + static readonly ConcurrentQueue logs = + new ConcurrentQueue(); + + // main thread id + static int mainThreadId; + +#if !UNITY_EDITOR + // Editor as of Unity 2021 does log threaded messages. + // only builds don't. + // do nothing in editor, otherwise we would log twice. + // before scene load ensures thread logs are all caught. + // otherwise some component's Awake may be called before we hooked it up. + // for example, ThreadedTransport's early logs wouldn't be caught. + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void Initialize() + { + + // set main thread id + mainThreadId = Thread.CurrentThread.ManagedThreadId; + + // receive threaded log calls + Application.logMessageReceivedThreaded -= OnLog; // remove old first. TODO unnecessary? + Application.logMessageReceivedThreaded += OnLog; + + // process logs on main thread Update + NetworkLoop.OnLateUpdate -= OnLateUpdate; // remove old first. TODO unnecessary? + NetworkLoop.OnLateUpdate += OnLateUpdate; + + // log for debugging + Debug.Log("ThreadLog initialized."); + } +#endif + + static bool IsMainThread() => + Thread.CurrentThread.ManagedThreadId == mainThreadId; + + // callback runs on the same thread where the Debug.Log is called. + // we can use this to buffer messages for main thread here. + static void OnLog(string message, string stackTrace, LogType type) + { + // only enqueue messages from other threads. + // otherwise OnLateUpdate main thread logging would be enqueued + // as well, causing deadlock. + if (IsMainThread()) return; + + // queue for logging from main thread later + logs.Enqueue(new LogEntry(Thread.CurrentThread.ManagedThreadId, type, message, stackTrace)); + } + + static void OnLateUpdate() + { + // process queued logs on main thread + while (logs.TryDequeue(out LogEntry entry)) + { + switch (entry.type) + { + // add [Thread#] prefix to make it super obvious where this log message comes from. + // some projects may see unexpected messages that were previously hidden, + // since Unity wouldn't log them without ThreadLog.cs. + case LogType.Log: + Debug.Log($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Warning: + Debug.LogWarning($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Error: + Debug.LogError($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Exception: + Debug.LogError($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + case LogType.Assert: + Debug.LogAssertion($"[Thread{entry.threadId}] {entry.message}\n{entry.stackTrace}"); + break; + } + } + } + } +} diff --git a/Assets/Mirror/Core/Threading/ThreadLog.cs.meta b/Assets/Mirror/Core/Threading/ThreadLog.cs.meta new file mode 100644 index 0000000..432955d --- /dev/null +++ b/Assets/Mirror/Core/Threading/ThreadLog.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 22360406b3844808b0a305486758a703 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Threading/ThreadLog.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Threading/WorkerThread.cs b/Assets/Mirror/Core/Threading/WorkerThread.cs new file mode 100644 index 0000000..f570dcc --- /dev/null +++ b/Assets/Mirror/Core/Threading/WorkerThread.cs @@ -0,0 +1,169 @@ +// worker thread for Unity (mischa 2022) +// thread with proper exception handling, profling, init, cleanup, etc. for Unity. +// use this from main thread. +using System; +using System.Diagnostics; +using System.Threading; +using UnityEngine.Profiling; +using Debug = UnityEngine.Debug; + +namespace Mirror +{ + public class WorkerThread + { + readonly Thread thread; + + protected volatile bool active; + + // stopwatch so we don't need to use Unity's Time (engine independent) + readonly Stopwatch watch = new Stopwatch(); + + // callbacks need to be set after constructor. + // inheriting classes can't pass their member funcs to base ctor. + // don't set them while the thread is running! + // -> Tick() returns a bool so it can easily stop the thread + // without needing to throw InterruptExceptions or similar. + public Action Init; + public Func Tick; + public Action Cleanup; + + public WorkerThread(string identifier) + { + // start the thread wrapped in safety guard + // if main application terminates, this thread needs to terminate too + thread = new Thread( + () => Guard(identifier) + ); + thread.IsBackground = true; + } + + public void Start() + { + // only if thread isn't already running + if (thread.IsAlive) + { + Debug.LogWarning("WorkerThread is still active, can't start it again."); + return; + } + + active = true; + thread.Start(); + } + + // signal the thread to stop gracefully. + // returns immediately, but the thread may take a while to stop. + // may be overwritten to clear more flags like 'computing' etc. + public virtual void SignalStop() => active = false; + + // wait for the thread to fully stop + public bool StopBlocking(float timeout) + { + // only if alive + if (!thread.IsAlive) return true; + + // double precision for long running servers. + watch.Restart(); + + // signal to stop + SignalStop(); + + // wait while thread is still alive + while (IsAlive) + { + // simply wait.. + Thread.Sleep(0); + + // deadlock detection + if (watch.Elapsed.TotalSeconds >= timeout) + { + // force kill all threads as last resort to stop them. + // return false to indicate deadlock. + Interrupt(); + return false; + } + } + return true; + } + + public bool IsAlive => thread.IsAlive; + + // signal an interrupt in the thread. + // this function is very safe to use. + // https://stackoverflow.com/questions/5950994/thread-abort-vs-thread-interrupt + // + // note this does not always kill the thread: + // "If this thread is not currently blocked in a wait, sleep, or join + // state, it will be interrupted when it next begins to block." + // https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.interrupt?view=net-6.0 + // + // in other words, "while (true) {}" wouldn't throw an interrupt exception. + // and that's _okay_. using interrupt is safe & best practice. + // => Unity still aborts deadlocked threads on script reload. + // => and we catch + warn on AbortException. + public void Interrupt() => thread.Interrupt(); + + // thread constructor needs callbacks. + // always define them, and make them call actions. + // those can be set at any time. + void OnInit() => Init?.Invoke(); + bool OnTick() => Tick?.Invoke() ?? false; + void OnCleanup() => Cleanup?.Invoke(); + + // guarded wrapper for thread code. + // catches exceptions which would otherwise be silent. + // shows in Unity profiler. + // etc. + public void Guard(string identifier) + { + try + { + // log when work begins = thread starts. + // very important for debugging threads. + Debug.Log($"{identifier}: started."); + + // show this thread in Unity profiler + Profiler.BeginThreadProfiling("Mirror Worker Threads", $"{identifier}"); + + // run init once + OnInit(); + + // run thread func while active + while (active) + { + // Tick() returns a bool so it can easily stop the thread + // without needing to throw InterruptExceptions or similar. + if (!OnTick()) break; + } + } + // Thread.Interrupt() will gracefully raise a InterruptedException. + catch (ThreadInterruptedException) + { + Debug.Log($"{identifier}: interrupted. That's okay."); + } + // Unity domain reload will cause a ThreadAbortException. + // for example, when saving a changed script while in play mode. + catch (ThreadAbortException) + { + Debug.LogWarning($"{identifier}: aborted. This may happen after domain reload. That's okay."); + } + catch (Exception e) + { + Debug.LogException(e); + } + finally + { + // run cleanup (if any) + active = false; + OnCleanup(); + + // remove this thread from Unity profiler + Profiler.EndThreadProfiling(); + + // log when work ends = thread terminates. + // very important for debugging threads. + // 'finally' to log no matter what (even if exceptions) + Debug.Log($"{identifier}: ended."); + } + } + } +} diff --git a/Assets/Mirror/Core/Threading/WorkerThread.cs.meta b/Assets/Mirror/Core/Threading/WorkerThread.cs.meta new file mode 100644 index 0000000..694601d --- /dev/null +++ b/Assets/Mirror/Core/Threading/WorkerThread.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 605fa1d7e32f40a08e5549bb43fc5c07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Threading/WorkerThread.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools.meta b/Assets/Mirror/Core/Tools.meta new file mode 100644 index 0000000..b8128f6 --- /dev/null +++ b/Assets/Mirror/Core/Tools.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d9c73cc2749d43268600b80df0b55c4d +timeCreated: 1667486812 diff --git a/Assets/Mirror/Core/Tools/AccurateInterval.cs b/Assets/Mirror/Core/Tools/AccurateInterval.cs new file mode 100644 index 0000000..9d2ce0e --- /dev/null +++ b/Assets/Mirror/Core/Tools/AccurateInterval.cs @@ -0,0 +1,86 @@ +// accurate interval from Mirror II. +// for sync / send intervals where it matters. +// does not(!) do catch-up. +// +// first, let's understand the problem. +// say we need an interval of 10 Hz, so every 100ms in Update we do: +// if (Time.time >= lastTime + interval) +// { +// lastTime = Time.time; +// ... +// } +// +// this seems fine, but actually Time.time will always be a few ms beyond +// the interval. but since lastTime is reset to Time.time, the remainder +// is always ignored away. +// with fixed tickRate servers (say 30 Hz), the remainder is significant! +// +// in practice if we have a 30 Hz tickRate server with a 30 Hz sendRate, +// the above way to measure the interval would result in a 18-19 Hz sendRate! +// => this is not just a little off. this is _way_ off, by almost half. +// => displaying actual + target tick/send rate will show this very easily. +// +// we need an accurate way to measure intervals for where it matters. +// and it needs to be testable to guarantee results. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class AccurateInterval + { + // static func instead of storing interval + lastTime struct. + // + don't need to initialize struct ctor with interval in Awake + // + allows for interval changes at runtime too + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Elapsed(double time, double interval, ref double lastTime) + { + // enough time elapsed? + if (time < lastTime + interval) + return false; + + // naive implementation: + //lastTime = time; + + // accurate but doesn't handle heavy load situations: + //lastTime += interval; + + // heavy load edge case: + // * interval is 100ms + // * server is under heavy load, Updates slow down to 1/s + // * Elapsed(1.000) returns true. + // technically 10 intervals have elapsed. + // * server recovers to normal, Updates are every 10ms again + // * Elapsed(1.010) should return false again until 1.100. + // + // increasing lastTime by interval would require 10 more calls + // to ever catch up again: + // lastTime += interval + // + // as result, the next 10 calls to Elapsed would return true. + // Elapsed(1.001) => true + // Elapsed(1.002) => true + // Elapsed(1.003) => true + // ... + // even though technically the delta was not >= interval. + // + // this would keep the server under heavy load, and it may never + // catch-up. this is not ideal for large virtual worlds. + // + // instead, we want to skip multiples of 'interval' and only + // keep the remainder. + // + // see also: AccurateIntervalTests.Slowdown() + + // easy to understand: + //double elapsed = time - lastTime; + //double remainder = elapsed % interval; + //lastTime = time - remainder; + + // easier: set to rounded multiples of interval (fholm). + // long to match double time. + long multiplier = (long)(time / interval); + lastTime = multiplier * interval; + return true; + } + } +} diff --git a/Assets/Mirror/Core/Tools/AccurateInterval.cs.meta b/Assets/Mirror/Core/Tools/AccurateInterval.cs.meta new file mode 100644 index 0000000..4c1f473 --- /dev/null +++ b/Assets/Mirror/Core/Tools/AccurateInterval.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c1b18064e25046f28b88db65a4012ec1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/AccurateInterval.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Compression.cs b/Assets/Mirror/Core/Tools/Compression.cs new file mode 100644 index 0000000..f6bd06f --- /dev/null +++ b/Assets/Mirror/Core/Tools/Compression.cs @@ -0,0 +1,596 @@ +// Quaternion compression from DOTSNET +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + /// Functions to Compress Quaternions and Floats + public static class Compression + { + // divide by precision (functions backported from Mirror II) + // for example, 0.1 cm precision converts '5.0f' float to '50' long. + // + // 'long' instead of 'int' to allow for large enough worlds. + // value / precision exceeds int.max range too easily. + // Convert.ToInt32/64 would throw. + // https://github.com/vis2k/DOTSNET/issues/59 + // + // 'long' and 'int' will result in the same bandwidth though. + // for example, ScaleToLong(10.5, 0.1) = 105. + // int: 0x00000069 + // long: 0x0000000000000069 + // delta compression will reduce both to 1 byte. + // + // returns + // 'true' if scaling was possible within 'long' bounds. + // 'false' if clamping was necessary. + // never throws. checking result is optional. + public static bool ScaleToLong(float value, float precision, out long result) + { + // user might try to pass precision = 0 to disable rounding. + // this is not supported. + // throw to make the user fix this immediately. + // otherwise we would have to reinterpret-cast if ==0 etc. + // this function should be kept simple. + // if rounding isn't wanted, this function shouldn't be called. + if (precision == 0) throw new DivideByZeroException($"ScaleToLong: precision=0 would cause null division. If rounding isn't wanted, don't call this function."); + + // catch OverflowException if value/precision > long.max. + // attackers should never be able to throw exceptions. + try + { + result = Convert.ToInt64(value / precision); + return true; + } + // clamp to .max/.min. + // returning '0' would make far away entities reset to origin. + // returning 'max' would keep them stuck at the end of the world. + // the latter is much easier to debug. + catch (OverflowException) + { + result = value > 0 ? long.MaxValue : long.MinValue; + return false; + } + } + + // returns + // 'true' if scaling was possible within 'long' bounds. + // 'false' if clamping was necessary. + // never throws. checking result is optional. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ScaleToLong(Vector3 value, float precision, out long x, out long y, out long z) + { + // attempt to convert every component. + // do not return early if one conversion returned 'false'. + // the return value is optional. always attempt to convert all. + bool result = true; + result &= ScaleToLong(value.x, precision, out x); + result &= ScaleToLong(value.y, precision, out y); + result &= ScaleToLong(value.z, precision, out z); + return result; + } + + // returns + // 'true' if scaling was possible within 'long' bounds. + // 'false' if clamping was necessary. + // never throws. checking result is optional. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ScaleToLong(Quaternion value, float precision, out long x, out long y, out long z, out long w) + { + // attempt to convert every component. + // do not return early if one conversion returned 'false'. + // the return value is optional. always attempt to convert all. + bool result = true; + result &= ScaleToLong(value.x, precision, out x); + result &= ScaleToLong(value.y, precision, out y); + result &= ScaleToLong(value.z, precision, out z); + result &= ScaleToLong(value.w, precision, out w); + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ScaleToLong(Vector3 value, float precision, out Vector3Long quantized) + { + quantized = Vector3Long.zero; + return ScaleToLong(value, precision, out quantized.x, out quantized.y, out quantized.z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ScaleToLong(Quaternion value, float precision, out Vector4Long quantized) + { + quantized = Vector4Long.zero; + return ScaleToLong(value, precision, out quantized.x, out quantized.y, out quantized.z, out quantized.w); + } + + // multiple by precision. + // for example, 0.1 cm precision converts '50' long to '5.0f' float. + public static float ScaleToFloat(long value, float precision) + { + // user might try to pass precision = 0 to disable rounding. + // this is not supported. + // throw to make the user fix this immediately. + // otherwise we would have to reinterpret-cast if ==0 etc. + // this function should be kept simple. + // if rounding isn't wanted, this function shouldn't be called. + if (precision == 0) throw new DivideByZeroException($"ScaleToLong: precision=0 would cause null division. If rounding isn't wanted, don't call this function."); + + return value * precision; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 ScaleToFloat(long x, long y, long z, float precision) + { + Vector3 v; + v.x = ScaleToFloat(x, precision); + v.y = ScaleToFloat(y, precision); + v.z = ScaleToFloat(z, precision); + return v; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Quaternion ScaleToFloat(long x, long y, long z, long w, float precision) + { + Quaternion v; + v.x = ScaleToFloat(x, precision); + v.y = ScaleToFloat(y, precision); + v.z = ScaleToFloat(z, precision); + v.w = ScaleToFloat(w, precision); + return v; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 ScaleToFloat(Vector3Long value, float precision) => + ScaleToFloat(value.x, value.y, value.z, precision); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Quaternion ScaleToFloat(Vector4Long value, float precision) => + ScaleToFloat(value.x, value.y, value.z, value.w, precision); + + // scale a float within min/max range to an ushort between min/max range + // note: can also use this for byte range from byte.MinValue to byte.MaxValue + public static ushort ScaleFloatToUShort(float value, float minValue, float maxValue, ushort minTarget, ushort maxTarget) + { + // note: C# ushort - ushort => int, hence so many casts + // max ushort - min ushort only fits into something bigger + int targetRange = maxTarget - minTarget; + float valueRange = maxValue - minValue; + float valueRelative = value - minValue; + return (ushort)(minTarget + (ushort)(valueRelative / valueRange * targetRange)); + } + + // scale an ushort within min/max range to a float between min/max range + // note: can also use this for byte range from byte.MinValue to byte.MaxValue + public static float ScaleUShortToFloat(ushort value, ushort minValue, ushort maxValue, float minTarget, float maxTarget) + { + // note: C# ushort - ushort => int, hence so many casts + float targetRange = maxTarget - minTarget; + ushort valueRange = (ushort)(maxValue - minValue); + ushort valueRelative = (ushort)(value - minValue); + return minTarget + (valueRelative / (float)valueRange * targetRange); + } + + // quaternion compression ////////////////////////////////////////////// + // smallest three: https://gafferongames.com/post/snapshot_compression/ + // compresses 16 bytes quaternion into 4 bytes + + // helper function to find largest absolute element + // returns the index of the largest one + public static int LargestAbsoluteComponentIndex(Vector4 value, out float largestAbs, out Vector3 withoutLargest) + { + // convert to abs + Vector4 abs = new Vector4(Mathf.Abs(value.x), Mathf.Abs(value.y), Mathf.Abs(value.z), Mathf.Abs(value.w)); + + // set largest to first abs (x) + largestAbs = abs.x; + withoutLargest = new Vector3(value.y, value.z, value.w); + int largestIndex = 0; + + // compare to the others, starting at second value + // performance for 100k calls + // for-loop: 25ms + // manual checks: 22ms + if (abs.y > largestAbs) + { + largestIndex = 1; + largestAbs = abs.y; + withoutLargest = new Vector3(value.x, value.z, value.w); + } + if (abs.z > largestAbs) + { + largestIndex = 2; + largestAbs = abs.z; + withoutLargest = new Vector3(value.x, value.y, value.w); + } + if (abs.w > largestAbs) + { + largestIndex = 3; + largestAbs = abs.w; + withoutLargest = new Vector3(value.x, value.y, value.z); + } + + return largestIndex; + } + + const float QuaternionMinRange = -0.707107f; + const float QuaternionMaxRange = 0.707107f; + const ushort TenBitsMax = 0b11_1111_1111; + + // note: assumes normalized quaternions + public static uint CompressQuaternion(Quaternion q) + { + // note: assuming normalized quaternions is enough. no need to force + // normalize here. we already normalize when decompressing. + + // find the largest component index [0,3] + value + int largestIndex = LargestAbsoluteComponentIndex(new Vector4(q.x, q.y, q.z, q.w), out float _, out Vector3 withoutLargest); + + // from here on, we work with the 3 components without largest! + + // "You might think you need to send a sign bit for [largest] in + // case it is negative, but you don’t, because you can make + // [largest] always positive by negating the entire quaternion if + // [largest] is negative. in quaternion space (x,y,z,w) and + // (-x,-y,-z,-w) represent the same rotation." + if (q[largestIndex] < 0) + withoutLargest = -withoutLargest; + + // put index & three floats into one integer. + // => index is 2 bits (4 values require 2 bits to store them) + // => the three floats are between [-0.707107,+0.707107] because: + // "If v is the absolute value of the largest quaternion + // component, the next largest possible component value occurs + // when two components have the same absolute value and the + // other two components are zero. The length of that quaternion + // (v,v,0,0) is 1, therefore v^2 + v^2 = 1, 2v^2 = 1, + // v = 1/sqrt(2). This means you can encode the smallest three + // components in [-0.707107,+0.707107] instead of [-1,+1] giving + // you more precision with the same number of bits." + // => the article recommends storing each float in 9 bits + // => our uint has 32 bits, so we might as well store in (32-2)/3=10 + // 10 bits max value: 1023=0x3FF (use OSX calc to flip 10 bits) + ushort aScaled = ScaleFloatToUShort(withoutLargest.x, QuaternionMinRange, QuaternionMaxRange, 0, TenBitsMax); + ushort bScaled = ScaleFloatToUShort(withoutLargest.y, QuaternionMinRange, QuaternionMaxRange, 0, TenBitsMax); + ushort cScaled = ScaleFloatToUShort(withoutLargest.z, QuaternionMinRange, QuaternionMaxRange, 0, TenBitsMax); + + // now we just need to pack them into one integer + // -> index is 2 bit and needs to be shifted to 31..32 + // -> a is 10 bit and needs to be shifted 20..30 + // -> b is 10 bit and needs to be shifted 10..20 + // -> c is 10 bit and needs to be at 0..10 + return (uint)(largestIndex << 30 | aScaled << 20 | bScaled << 10 | cScaled); + } + + // Quaternion normalizeSAFE from ECS math.normalizesafe() + // => useful to produce valid quaternions even if client sends invalid + // data + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static Quaternion QuaternionNormalizeSafe(Quaternion value) + { + // The smallest positive normal number representable in a float. + const float FLT_MIN_NORMAL = 1.175494351e-38F; + + Vector4 v = new Vector4(value.x, value.y, value.z, value.w); + float length = Vector4.Dot(v, v); + return length > FLT_MIN_NORMAL + ? value.normalized + : Quaternion.identity; + } + + // note: gives normalized quaternions + public static Quaternion DecompressQuaternion(uint data) + { + // get cScaled which is at 0..10 and ignore the rest + ushort cScaled = (ushort)(data & TenBitsMax); + + // get bScaled which is at 10..20 and ignore the rest + ushort bScaled = (ushort)((data >> 10) & TenBitsMax); + + // get aScaled which is at 20..30 and ignore the rest + ushort aScaled = (ushort)((data >> 20) & TenBitsMax); + + // get 2 bit largest index, which is at 31..32 + int largestIndex = (int)(data >> 30); + + // scale back to floats + float a = ScaleUShortToFloat(aScaled, 0, TenBitsMax, QuaternionMinRange, QuaternionMaxRange); + float b = ScaleUShortToFloat(bScaled, 0, TenBitsMax, QuaternionMinRange, QuaternionMaxRange); + float c = ScaleUShortToFloat(cScaled, 0, TenBitsMax, QuaternionMinRange, QuaternionMaxRange); + + // calculate the omitted component based on a²+b²+c²+d²=1 + float d = Mathf.Sqrt(1 - a*a - b*b - c*c); + + // reconstruct based on largest index + Vector4 value; + switch (largestIndex) + { + case 0: value = new Vector4(d, a, b, c); break; + case 1: value = new Vector4(a, d, b, c); break; + case 2: value = new Vector4(a, b, d, c); break; + default: value = new Vector4(a, b, c, d); break; + } + + // ECS Rotation only works with normalized quaternions. + // make sure that's always the case here to avoid ECS bugs where + // everything stops moving if the quaternion isn't normalized. + // => NormalizeSafe returns a normalized quaternion even if we pass + // in NaN from deserializing invalid values! + return QuaternionNormalizeSafe(new Quaternion(value.x, value.y, value.z, value.w)); + } + + // varint compression ////////////////////////////////////////////////// + // helper function to predict varint size for a given number. + // useful when checking if a message + size header will fit, etc. + public static int VarUIntSize(ulong value) + { + if (value <= 240) + return 1; + if (value <= 2287) + return 2; + if (value <= 67823) + return 3; + if (value <= 16777215) + return 4; + if (value <= 4294967295) + return 5; + if (value <= 1099511627775) + return 6; + if (value <= 281474976710655) + return 7; + if (value <= 72057594037927935) + return 8; + return 9; + } + + // helper function to predict varint size for a given number. + // useful when checking if a message + size header will fit, etc. + public static int VarIntSize(long value) + { + // CompressVarInt zigzags it first + ulong zigzagged = (ulong)((value >> 63) ^ (value << 1)); + return VarUIntSize(zigzagged); + } + + // compress ulong varint. + // same result for ulong, uint, ushort and byte. only need one function. + // NOT an extension. otherwise weaver might accidentally use it. + public static void CompressVarUInt(NetworkWriter writer, ulong value) + { + // straight forward implementation: + // keep this for understanding & debugging. + /* + if (value <= 240) + { + writer.WriteByte((byte)value); + return; + } + if (value <= 2287) + { + writer.WriteByte((byte)(((value - 240) >> 8) + 241)); + writer.WriteByte((byte)((value - 240) & 0xFF)); + return; + } + if (value <= 67823) + { + writer.WriteByte((byte)249); + writer.WriteByte((byte)((value - 2288) >> 8)); + writer.WriteByte((byte)((value - 2288) & 0xFF)); + return; + } + if (value <= 16777215) + { + writer.WriteByte((byte)250); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + return; + } + if (value <= 4294967295) + { + writer.WriteByte((byte)251); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + writer.WriteByte((byte)((value >> 24) & 0xFF)); + return; + } + if (value <= 1099511627775) + { + writer.WriteByte((byte)252); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + writer.WriteByte((byte)((value >> 24) & 0xFF)); + writer.WriteByte((byte)((value >> 32) & 0xFF)); + return; + } + if (value <= 281474976710655) + { + writer.WriteByte((byte)253); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + writer.WriteByte((byte)((value >> 24) & 0xFF)); + writer.WriteByte((byte)((value >> 32) & 0xFF)); + writer.WriteByte((byte)((value >> 40) & 0xFF)); + return; + } + if (value <= 72057594037927935) + { + writer.WriteByte((byte)254); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + writer.WriteByte((byte)((value >> 24) & 0xFF)); + writer.WriteByte((byte)((value >> 32) & 0xFF)); + writer.WriteByte((byte)((value >> 40) & 0xFF)); + writer.WriteByte((byte)((value >> 48) & 0xFF)); + return; + } + + // all others + { + writer.WriteByte((byte)255); + writer.WriteByte((byte)(value & 0xFF)); + writer.WriteByte((byte)((value >> 8) & 0xFF)); + writer.WriteByte((byte)((value >> 16) & 0xFF)); + writer.WriteByte((byte)((value >> 24) & 0xFF)); + writer.WriteByte((byte)((value >> 32) & 0xFF)); + writer.WriteByte((byte)((value >> 40) & 0xFF)); + writer.WriteByte((byte)((value >> 48) & 0xFF)); + writer.WriteByte((byte)((value >> 56) & 0xFF)); + } + */ + + // faster implementation writes multiple bytes at once. + // avoids extra Space, WriteBlittable overhead. + // VarInt is in hot path, performance matters here. + if (value <= 240) + { + byte a = (byte)value; + writer.WriteByte(a); + return; + } + if (value <= 2287) + { + byte a = (byte)(((value - 240) >> 8) + 241); + byte b = (byte)((value - 240) & 0xFF); + writer.WriteUShort((ushort)(b << 8 | a)); + return; + } + if (value <= 67823) + { + byte a = (byte)249; + byte b = (byte)((value - 2288) >> 8); + byte c = (byte)((value - 2288) & 0xFF); + writer.WriteByte(a); + writer.WriteUShort((ushort)(c << 8 | b)); + return; + } + if (value <= 16777215) + { + byte a = (byte)250; + uint b = (uint)(value << 8); + writer.WriteUInt(b | a); + return; + } + if (value <= 4294967295) + { + byte a = (byte)251; + uint b = (uint)value; + writer.WriteByte(a); + writer.WriteUInt(b); + return; + } + if (value <= 1099511627775) + { + byte a = (byte)252; + byte b = (byte)(value & 0xFF); + uint c = (uint)(value >> 8); + writer.WriteUShort((ushort)(b << 8 | a)); + writer.WriteUInt(c); + return; + } + if (value <= 281474976710655) + { + byte a = (byte)253; + byte b = (byte)(value & 0xFF); + byte c = (byte)((value >> 8) & 0xFF); + uint d = (uint)(value >> 16); + writer.WriteByte(a); + writer.WriteUShort((ushort)(c << 8 | b)); + writer.WriteUInt(d); + return; + } + if (value <= 72057594037927935) + { + byte a = 254; + ulong b = value << 8; + writer.WriteULong(b | a); + return; + } + + // all others + { + writer.WriteByte(255); + writer.WriteULong(value); + } + } + + // zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CompressVarInt(NetworkWriter writer, long i) + { + ulong zigzagged = (ulong)((i >> 63) ^ (i << 1)); + CompressVarUInt(writer, zigzagged); + } + + // NOT an extension. otherwise weaver might accidentally use it. + public static ulong DecompressVarUInt(NetworkReader reader) + { + byte a0 = reader.ReadByte(); + if (a0 < 241) + { + return a0; + } + + byte a1 = reader.ReadByte(); + if (a0 <= 248) + { + return 240 + ((a0 - (ulong)241) << 8) + a1; + } + + byte a2 = reader.ReadByte(); + if (a0 == 249) + { + return 2288 + ((ulong)a1 << 8) + a2; + } + + byte a3 = reader.ReadByte(); + if (a0 == 250) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16); + } + + byte a4 = reader.ReadByte(); + if (a0 == 251) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24); + } + + byte a5 = reader.ReadByte(); + if (a0 == 252) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32); + } + + byte a6 = reader.ReadByte(); + if (a0 == 253) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40); + } + + byte a7 = reader.ReadByte(); + if (a0 == 254) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48); + } + + byte a8 = reader.ReadByte(); + if (a0 == 255) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48) + (((ulong)a8) << 56); + } + + throw new IndexOutOfRangeException($"DecompressVarInt failure: {a0}"); + } + + // zigzag decoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long DecompressVarInt(NetworkReader reader) + { + ulong data = DecompressVarUInt(reader); + return ((long)(data >> 1)) ^ -((long)data & 1); + } + } +} diff --git a/Assets/Mirror/Core/Tools/Compression.cs.meta b/Assets/Mirror/Core/Tools/Compression.cs.meta new file mode 100644 index 0000000..e6308ca --- /dev/null +++ b/Assets/Mirror/Core/Tools/Compression.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5c28963f9c4b97e418252a55500fb91e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Compression.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/DeltaCompression.cs b/Assets/Mirror/Core/Tools/DeltaCompression.cs new file mode 100644 index 0000000..50b9b2f --- /dev/null +++ b/Assets/Mirror/Core/Tools/DeltaCompression.cs @@ -0,0 +1,58 @@ +// manual delta compression for some types. +// varint(b-a) +// Mirror can't use Mirror II's bit-tree delta compression. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class DeltaCompression + { + // delta (usually small), then zigzag varint to support +- changes + // parameter order: (last, current) makes most sense (Q3 does this too). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Compress(NetworkWriter writer, long last, long current) => + Compression.CompressVarInt(writer, current - last); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Decompress(NetworkReader reader, long last) => + last + Compression.DecompressVarInt(reader); + + // delta (usually small), then zigzag varint to support +- changes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Compress(NetworkWriter writer, Vector3Long last, Vector3Long current) + { + Compress(writer, last.x, current.x); + Compress(writer, last.y, current.y); + Compress(writer, last.z, current.z); + } + + // delta (usually small), then zigzag varint to support +- changes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Compress(NetworkWriter writer, Vector4Long last, Vector4Long current) + { + Compress(writer, last.x, current.x); + Compress(writer, last.y, current.y); + Compress(writer, last.z, current.z); + Compress(writer, last.w, current.w); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long Decompress(NetworkReader reader, Vector3Long last) + { + long x = Decompress(reader, last.x); + long y = Decompress(reader, last.y); + long z = Decompress(reader, last.z); + return new Vector3Long(x, y, z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long Decompress(NetworkReader reader, Vector4Long last) + { + long x = Decompress(reader, last.x); + long y = Decompress(reader, last.y); + long z = Decompress(reader, last.z); + long w = Decompress(reader, last.w); + return new Vector4Long(x, y, z, w); + } + } +} diff --git a/Assets/Mirror/Core/Tools/DeltaCompression.cs.meta b/Assets/Mirror/Core/Tools/DeltaCompression.cs.meta new file mode 100644 index 0000000..83a4d41 --- /dev/null +++ b/Assets/Mirror/Core/Tools/DeltaCompression.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6b8f3fffcb4754c15bc5ed4c33e2497b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/DeltaCompression.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs new file mode 100644 index 0000000..674abb8 --- /dev/null +++ b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs @@ -0,0 +1,53 @@ +// N-day EMA implementation from Mirror with a few changes (struct etc.) +// it calculates an exponential moving average roughly equivalent to the last n observations +// https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average +using System; + +namespace Mirror +{ + public struct ExponentialMovingAverage + { + readonly double alpha; + bool initialized; + + public double Value; + public double Variance; + public double StandardDeviation; // absolute value, see test + + public ExponentialMovingAverage(int n) + { + // standard N-day EMA alpha calculation + alpha = 2.0 / (n + 1); + initialized = false; + Value = 0; + Variance = 0; + StandardDeviation = 0; + } + + public void Add(double newValue) + { + // simple algorithm for EMA described here: + // https://en.wikipedia.org/wiki/Moving_average#Exponentially_weighted_moving_variance_and_standard_deviation + if (initialized) + { + double delta = newValue - Value; + Value += alpha * delta; + Variance = (1 - alpha) * (Variance + alpha * delta * delta); + StandardDeviation = Math.Sqrt(Variance); + } + else + { + Value = newValue; + initialized = true; + } + } + + public void Reset() + { + initialized = false; + Value = 0; + Variance = 0; + StandardDeviation = 0; + } + } +} diff --git a/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs.meta b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs.meta new file mode 100644 index 0000000..533ab12 --- /dev/null +++ b/Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 05e858cbaa54b4ce4a48c8c7f50c1914 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/ExponentialMovingAverage.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Extensions.cs b/Assets/Mirror/Core/Tools/Extensions.cs new file mode 100644 index 0000000..e9399b3 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Extensions.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirror +{ + public static class Extensions + { + public static string ToHexString(this ArraySegment segment) => + BitConverter.ToString(segment.Array, segment.Offset, segment.Count); + + // string.GetHashCode is not guaranteed to be the same on all + // machines, but we need one that is the same on all machines. + // Uses fnv1a as hash function for more uniform distribution http://www.isthe.com/chongo/tech/comp/fnv/ + // Tests: https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + // NOTE: Do not call this from hot path because it's slow O(N) for long method names. + // - As of 2012-02-16 There are 2 design-time callers (weaver) and 1 runtime caller that caches. + public static int GetStableHashCode(this string text) + { + unchecked + { + uint hash = 0x811c9dc5; + uint prime = 0x1000193; + + for (int i = 0; i < text.Length; ++i) + { + byte value = (byte)text[i]; + hash = hash ^ value; + hash *= prime; + } + + //UnityEngine.Debug.Log($"Created stable hash {(ushort)hash} for {text}"); + return (int)hash; + } + } + + // smaller version of our GetStableHashCode. + // careful, this significantly increases chance of collisions. + public static ushort GetStableHashCode16(this string text) + { + // deterministic hash + int hash = GetStableHashCode(text); + + // Gets the 32bit fnv1a hash + // To get it down to 16bit but still reduce hash collisions we cant just cast it to ushort + // Instead we take the highest 16bits of the 32bit hash and fold them with xor into the lower 16bits + // This will create a more uniform 16bit hash, the method is described in: + // http://www.isthe.com/chongo/tech/comp/fnv/ in section "Changing the FNV hash size - xor-folding" + return (ushort)((hash >> 16) ^ hash); + } + + // previously in DotnetCompatibility.cs + // leftover from the UNET days. supposedly for windows store? + public static string GetMethodName(this Delegate func) + { +#if NETFX_CORE + return func.GetMethodInfo().Name; +#else + return func.Method.Name; +#endif + } + + // helper function to copy to List + // C# only provides CopyTo(T[]) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(this IEnumerable source, List destination) + { + // foreach allocates. use AddRange. + destination.AddRange(source); + } + +#if !UNITY_2021_OR_NEWER + // Unity 2020 and earlier don't have Queue.TryDequeue which we need for batching. + public static bool TryDequeue(this Queue source, out T element) + { + if (source.Count > 0) + { + element = source.Dequeue(); + return true; + } + + element = default; + return false; + } +#endif + +#if !UNITY_2021_OR_NEWER + // Unity 2020 and earlier don't have ConcurrentQueue.Clear which we need for ThreadedTransport. + public static void Clear(this ConcurrentQueue source) + { + // while count > 0 risks deadlock if other thread write at the same time. + // our safest solution is a best-effort approach to clear 'Count' once. + int count = source.Count; // get it only once + for (int i = 0; i < count; ++i) + { + source.TryDequeue(out _); + } + } +#endif + +#if !UNITY_2021_3_OR_NEWER + // Some patch versions of Unity 2021.3 and earlier don't have transform.GetPositionAndRotation which we use for performance in some places + public static void GetPositionAndRotation(this Transform transform, out Vector3 position, out Quaternion rotation) + { + position = transform.position; + rotation = transform.rotation; + } + + public static void SetPositionAndRotation(this Transform transform, Vector3 position, Quaternion rotation) + { + transform.position = position; + transform.rotation = rotation; + } + + public static void GetLocalPositionAndRotation(this Transform transform, out Vector3 position, out Quaternion rotation) + { + position = transform.localPosition; + rotation = transform.localRotation; + } + + public static void SetLocalPositionAndRotation(this Transform transform, Vector3 position, Quaternion rotation) + { + transform.localPosition = position; + transform.localRotation = rotation; + } +#endif + + // IPEndPoint address only to pretty string. + // useful for to get a connection's address for IP bans etc. + public static string PrettyAddress(this IPEndPoint endPoint) + { + if (endPoint == null) return ""; + + // Map to IPv4 if "IsIPv4MappedToIPv6" for readability + // "::ffff:127.0.0.1" -> "127.0.0.1" + return + endPoint.Address.IsIPv4MappedToIPv6 + ? endPoint.Address.MapToIPv4().ToString() + : endPoint.Address.ToString(); + } + } +} diff --git a/Assets/Mirror/Core/Tools/Extensions.cs.meta b/Assets/Mirror/Core/Tools/Extensions.cs.meta new file mode 100644 index 0000000..13bd75f --- /dev/null +++ b/Assets/Mirror/Core/Tools/Extensions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: decf32fd053744d18f35712b7a6f5116 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Extensions.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Half.cs b/Assets/Mirror/Core/Tools/Half.cs new file mode 100644 index 0000000..33eb08e --- /dev/null +++ b/Assets/Mirror/Core/Tools/Half.cs @@ -0,0 +1,773 @@ +// half float from .NET 5: +// https://devblogs.microsoft.com/dotnet/introducing-the-half-type/ +// +// drop in from dotnet/runtime source: +// https://github.com/dotnet/runtime/blob/e188d6ac90fe56320cca51c53709ef1c72f063d5/src/libraries/System.Private.CoreLib/src/System/Half.cs#L17 +// removing all the stuff that's not in Unity though. + + + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace System +{ + // Portions of the code implemented below are based on the 'Berkeley SoftFloat Release 3e' algorithms. + + /// + /// Represents a half-precision floating-point number. + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct Half + : IComparable, + IComparable, + IEquatable + { + private const NumberStyles DefaultParseStyle = NumberStyles.Float | NumberStyles.AllowThousands; + + // Constants for manipulating the private bit-representation + + internal const ushort SignMask = 0x8000; + internal const int SignShift = 15; + internal const byte ShiftedSignMask = SignMask >> SignShift; + + internal const ushort BiasedExponentMask = 0x7C00; + internal const int BiasedExponentShift = 10; + internal const int BiasedExponentLength = 5; + internal const byte ShiftedBiasedExponentMask = BiasedExponentMask >> BiasedExponentShift; + + internal const ushort TrailingSignificandMask = 0x03FF; + + internal const byte MinSign = 0; + internal const byte MaxSign = 1; + + internal const byte MinBiasedExponent = 0x00; + internal const byte MaxBiasedExponent = 0x1F; + + internal const byte ExponentBias = 15; + + internal const sbyte MinExponent = -14; + internal const sbyte MaxExponent = +15; + + internal const ushort MinTrailingSignificand = 0x0000; + internal const ushort MaxTrailingSignificand = 0x03FF; + + internal const int TrailingSignificandLength = 10; + internal const int SignificandLength = TrailingSignificandLength + 1; + + // Constants representing the private bit-representation for various default values + + private const ushort PositiveZeroBits = 0x0000; + private const ushort NegativeZeroBits = 0x8000; + + private const ushort EpsilonBits = 0x0001; + + private const ushort PositiveInfinityBits = 0x7C00; + private const ushort NegativeInfinityBits = 0xFC00; + + private const ushort PositiveQNaNBits = 0x7E00; + private const ushort NegativeQNaNBits = 0xFE00; + + private const ushort MinValueBits = 0xFBFF; + private const ushort MaxValueBits = 0x7BFF; + + private const ushort PositiveOneBits = 0x3C00; + private const ushort NegativeOneBits = 0xBC00; + + private const ushort SmallestNormalBits = 0x0400; + + private const ushort EBits = 0x4170; + private const ushort PiBits = 0x4248; + private const ushort TauBits = 0x4648; + + // Well-defined and commonly used values + + public static Half Epsilon => new Half(EpsilonBits); // 5.9604645E-08 + + public static Half PositiveInfinity => new Half(PositiveInfinityBits); // 1.0 / 0.0; + + public static Half NegativeInfinity => new Half(NegativeInfinityBits); // -1.0 / 0.0 + + public static Half NaN => new Half(NegativeQNaNBits); // 0.0 / 0.0 + + public static Half MinValue => new Half(MinValueBits); // -65504 + + public static Half MaxValue => new Half(MaxValueBits); // 65504 + + internal readonly ushort _value; // internal representation + + internal Half(ushort value) + { + _value = value; + } + + private Half(bool sign, ushort exp, ushort sig) => _value = (ushort)(((sign ? 1 : 0) << SignShift) + (exp << BiasedExponentShift) + sig); + + internal byte BiasedExponent + { + get + { + ushort bits = _value; + return ExtractBiasedExponentFromBits(bits); + } + } + + internal sbyte Exponent + { + get + { + return (sbyte)(BiasedExponent - ExponentBias); + } + } + + internal ushort Significand + { + get + { + return (ushort)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U)); + } + } + + internal ushort TrailingSignificand + { + get + { + ushort bits = _value; + return ExtractTrailingSignificandFromBits(bits); + } + } + + internal static byte ExtractBiasedExponentFromBits(ushort bits) + { + return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask); + } + + internal static ushort ExtractTrailingSignificandFromBits(ushort bits) + { + return (ushort)(bits & TrailingSignificandMask); + } + + public static bool operator <(Half left, Half right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative && !AreZero(left, right); + } + + return (left._value != right._value) && ((left._value < right._value) ^ leftIsNegative); + } + + public static bool operator >(Half left, Half right) + { + return right < left; + } + + public static bool operator <=(Half left, Half right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative || AreZero(left, right); + } + + return (left._value == right._value) || ((left._value < right._value) ^ leftIsNegative); + } + + public static bool operator >=(Half left, Half right) + { + return right <= left; + } + + public static bool operator ==(Half left, Half right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + + // IEEE defines that positive and negative zero are equivalent. + return (left._value == right._value) || AreZero(left, right); + } + + public static bool operator !=(Half left, Half right) + { + return !(left == right); + } + + /// Determines whether the specified value is finite (zero, subnormal, or normal). + /// This effectively checks the value is not NaN and not infinite. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsFinite(Half value) + { + uint bits = value._value; + return (~bits & PositiveInfinityBits) != 0; + } + + /// Determines whether the specified value is infinite. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsInfinity(Half value) + { + uint bits = value._value; + return (bits & ~SignMask) == PositiveInfinityBits; + } + + /// Determines whether the specified value is NaN. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNaN(Half value) + { + uint bits = value._value; + return (bits & ~SignMask) > PositiveInfinityBits; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsNaNOrZero(Half value) + { + uint bits = value._value; + return ((bits - 1) & ~SignMask) >= PositiveInfinityBits; + } + + /// Determines whether the specified value is negative. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNegative(Half value) + { + return (short)(value._value) < 0; + } + + /// Determines whether the specified value is negative infinity. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNegativeInfinity(Half value) + { + return value._value == NegativeInfinityBits; + } + + /// Determines whether the specified value is normal (finite, but not zero or subnormal). + /// This effectively checks the value is not NaN, not infinite, not subnormal, and not zero. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNormal(Half value) + { + uint bits = value._value; + return (ushort)((bits & ~SignMask) - SmallestNormalBits) < (PositiveInfinityBits - SmallestNormalBits); + } + + /// Determines whether the specified value is positive infinity. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsPositiveInfinity(Half value) + { + return value._value == PositiveInfinityBits; + } + + /// Determines whether the specified value is subnormal (finite, but not zero or normal). + /// This effectively checks the value is not NaN, not infinite, not normal, and not zero. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsSubnormal(Half value) + { + uint bits = value._value; + return (ushort)((bits & ~SignMask) - 1) < MaxTrailingSignificand; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool IsZero(Half value) + { + uint bits = value._value; + return (bits & ~SignMask) == 0; + } + + private static bool AreZero(Half left, Half right) + { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return ((left._value | right._value) & ~SignMask) == 0; + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// A value less than zero if this is less than , zero if this is equal to , or a value greater than zero if this is greater than . + public int CompareTo(object obj) + { + if (obj is Half other) + { + return CompareTo(other); + } + return (obj is null) ? 1 : throw new ArgumentException("SR.Arg_MustBeHalf"); + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// A value less than zero if this is less than , zero if this is equal to , or a value greater than zero if this is greater than . + public int CompareTo(Half other) + { + if (this < other) + { + return -1; + } + + if (this > other) + { + return 1; + } + + if (this == other) + { + return 0; + } + + if (IsNaN(this)) + { + return IsNaN(other) ? 0 : -1; + } + + return 1; + } + + /// + /// Returns a value that indicates whether this instance is equal to a specified . + /// + public override bool Equals(object obj) + { + return (obj is Half other) && Equals(other); + } + + /// + /// Returns a value that indicates whether this instance is equal to a specified value. + /// + public bool Equals(Half other) + { + return _value == other._value + || AreZero(this, other) + || (IsNaN(this) && IsNaN(other)); + } + + /// + /// Serves as the default hash function. + /// + public override int GetHashCode() + { + uint bits = _value; + + if (IsNaNOrZero(this)) + { + // Ensure that all NaNs and both zeros have the same hash code + bits &= PositiveInfinityBits; + } + + return (int)bits; + } + + /// + /// Returns a string representation of the current value. + /// + public override string ToString() + { + return ((float)this).ToString(); + } + + // + // Explicit Convert To Half + // + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + public static explicit operator Half(char value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + public static explicit operator Half(decimal value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(short value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(int value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(long value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(float value) + { + // Unity implement this! + return new Half(Mathf.FloatToHalf(value)); + } + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(ushort value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(uint value) => (Half)(float)value; + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Half(ulong value) => (Half)(float)value; + + // + // Explicit Convert From Half + // + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator byte(Half value) => (byte)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator char(Half value) => (char)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator decimal(Half value) => (decimal)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator short(Half value) => (short)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator int(Half value) => (int)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator long(Half value) => (long)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator sbyte(Half value) => (sbyte)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator ushort(Half value) => (ushort)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator uint(Half value) => (uint)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator ulong(Half value) => (ulong)(float)value; + + // + // Implicit Convert To Half + // + + /// Implicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static implicit operator Half(byte value) => (Half)(float)value; + + /// Implicitly converts a value to its nearest representable half-precision floating-point value. + /// converted to its nearest representable half-precision floating-point value. + public static implicit operator Half(sbyte value) => (Half)(float)value; + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// converted to its nearest representable value. + public static explicit operator float(Half value) + { + return Mathf.HalfToFloat(value._value); + } + + // IEEE 754 specifies NaNs to be propagated + internal static Half Negate(Half value) + { + return IsNaN(value) ? value : new Half((ushort)(value._value ^ SignMask)); + } + + public static Half operator +(Half left, Half right) => (Half)((float)left + (float)right); + + // + // IDecrementOperators + // + + public static Half operator --(Half value) + { + var tmp = (float)value; + --tmp; + return (Half)tmp; + } + + // + // IDivisionOperators + // + + public static Half operator /(Half left, Half right) => (Half)((float)left / (float)right); + + // + // IExponentialFunctions + // + + public static Half Exp(Half x) => (Half)Math.Exp((float)x); + + // + // IFloatingPoint + // + + public static Half Ceiling(Half x) => (Half)Math.Ceiling((float)x); + + public static Half Floor(Half x) => (Half)Math.Floor((float)x); + + public static Half Round(Half x) => (Half)Math.Round((float)x); + + public static Half Round(Half x, int digits) => (Half)Math.Round((float)x, digits); + + public static Half Round(Half x, MidpointRounding mode) => (Half)Math.Round((float)x, mode); + + public static Half Round(Half x, int digits, MidpointRounding mode) => (Half)Math.Round((float)x, digits, mode); + + public static Half Truncate(Half x) => (Half)Math.Truncate((float)x); + + // + // IFloatingPointConstants + // + + public static Half E => new Half(EBits); + + public static Half Pi => new Half(PiBits); + + public static Half Tau => new Half(TauBits); + + // + // IFloatingPointIeee754 + // + + public static Half NegativeZero => new Half(NegativeZeroBits); + + public static Half Atan2(Half y, Half x) => (Half)Math.Atan2((float)y, (float)x); + + public static Half Lerp(Half value1, Half value2, Half amount) => (Half)Mathf.Lerp((float)value1, (float)value2, (float)amount); + + // + // IHyperbolicFunctions + // + + public static Half Cosh(Half x) => (Half)Math.Cosh((float)x); + + public static Half Sinh(Half x) => (Half)Math.Sinh((float)x); + + public static Half Tanh(Half x) => (Half)Math.Tanh((float)x); + + // + // IIncrementOperators + // + + public static Half operator ++(Half value) + { + var tmp = (float)value; + ++tmp; + return (Half)tmp; + } + + // + // ILogarithmicFunctions + // + + public static Half Log(Half x) => (Half)Math.Log((float)x); + + public static Half Log(Half x, Half newBase) => (Half)Math.Log((float)x, (float)newBase); + + // + // IModulusOperators + // + + public static Half operator %(Half left, Half right) => (Half)((float)left % (float)right); + + // + // IMultiplicativeIdentity + // + + public static Half MultiplicativeIdentity => new Half(PositiveOneBits); + + // + // IMultiplyOperators + // + + public static Half operator *(Half left, Half right) => (Half)((float)left * (float)right); + + // + // INumber + // + + public static Half Clamp(Half value, Half min, Half max) => (Half)Mathf.Clamp((float)value, (float)min, (float)max); + + public static Half CopySign(Half value, Half sign) + { + // This method is required to work for all inputs, + // including NaN, so we operate on the raw bits. + uint xbits = value._value; + uint ybits = sign._value; + + // Remove the sign from x, and remove everything but the sign from y + // Then, simply OR them to get the correct sign + return new Half((ushort)((xbits & ~SignMask) | (ybits & SignMask))); + } + + public static Half Max(Half x, Half y) => (Half)Math.Max((float)x, (float)y); + + public static Half MaxNumber(Half x, Half y) + { + // This matches the IEEE 754:2019 `maximumNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the larger of the inputs. It + // treats +0 as larger than -0 as per the specification. + + if (x != y) + { + if (!IsNaN(y)) + { + return y < x ? x : y; + } + + return x; + } + + return IsNegative(y) ? x : y; + } + + public static Half Min(Half x, Half y) => (Half)Math.Min((float)x, (float)y); + + public static Half MinNumber(Half x, Half y) + { + // This matches the IEEE 754:2019 `minimumNumber` function + // + // It does not propagate NaN inputs back to the caller and + // otherwise returns the larger of the inputs. It + // treats +0 as larger than -0 as per the specification. + + if (x != y) + { + if (!IsNaN(y)) + { + return x < y ? x : y; + } + + return x; + } + + return IsNegative(x) ? x : y; + } + + public static int Sign(Half value) + { + if (IsNaN(value)) + { + throw new ArithmeticException("SR.Arithmetic_NaN"); + } + + if (IsZero(value)) + { + return 0; + } + else if (IsNegative(value)) + { + return -1; + } + + return +1; + } + + // + // INumberBase + // + + public static Half One => new Half(PositiveOneBits); + + public static Half Zero => new Half(PositiveZeroBits); + + public static Half Abs(Half value) => new Half((ushort)(value._value & ~SignMask)); + + public static bool IsPositive(Half value) => (short)(value._value) >= 0; + + public static bool IsRealNumber(Half value) + { + // A NaN will never equal itself so this is an + // easy and efficient way to check for a real number. + +#pragma warning disable CS1718 + return value == value; +#pragma warning restore CS1718 + } + + // + // IPowerFunctions + // + + public static Half Pow(Half x, Half y) => (Half)Math.Pow((float)x, (float)y); + + // + // IRootFunctions + // + + public static Half Sqrt(Half x) => (Half)Math.Sqrt((float)x); + + // + // ISignedNumber + // + + public static Half NegativeOne => new Half(NegativeOneBits); + + // + // ISubtractionOperators + // + + public static Half operator -(Half left, Half right) => (Half)((float)left - (float)right); + + // + // ITrigonometricFunctions + // + + public static Half Acos(Half x) => (Half)Math.Acos((float)x); + + public static Half Asin(Half x) => (Half)Math.Asin((float)x); + + public static Half Atan(Half x) => (Half)Math.Atan((float)x); + + public static Half Cos(Half x) => (Half)Math.Cos((float)x); + + public static Half Sin(Half x) => (Half)Math.Sin((float)x); + + public static Half Tan(Half x) => (Half)Math.Tan((float)x); + + // + // IUnaryNegationOperators + // + + public static Half operator -(Half value) => (Half)(-(float)value); + + // + // IUnaryPlusOperators + // + + public static Half operator +(Half value) => value; + } +} diff --git a/Assets/Mirror/Core/Tools/Half.cs.meta b/Assets/Mirror/Core/Tools/Half.cs.meta new file mode 100644 index 0000000..030a09a --- /dev/null +++ b/Assets/Mirror/Core/Tools/Half.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 70b5947c49174f3c90121edd21ea6b15 +timeCreated: 1729783714 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Half.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Mathd.cs b/Assets/Mirror/Core/Tools/Mathd.cs new file mode 100644 index 0000000..374471a --- /dev/null +++ b/Assets/Mirror/Core/Tools/Mathd.cs @@ -0,0 +1,32 @@ +// 'double' precision variants for some of Unity's Mathf functions. +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public static class Mathd + { + // Unity 2020 doesn't have Math.Clamp yet. + /// Clamps value between 0 and 1 and returns value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Clamp(double value, double min, double max) + { + if (value < min) return min; + if (value > max) return max; + return value; + } + + /// Clamps value between 0 and 1 and returns value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double Clamp01(double value) => Clamp(value, 0, 1); + + /// Calculates the linear parameter t that produces the interpolant value within the range [a, b]. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double InverseLerp(double a, double b, double value) => + a != b ? Clamp01((value - a) / (b - a)) : 0; + + /// Linearly interpolates between a and b by t with no limit to t. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double LerpUnclamped(double a, double b, double t) => + a + (b - a) * t; + } +} diff --git a/Assets/Mirror/Core/Tools/Mathd.cs.meta b/Assets/Mirror/Core/Tools/Mathd.cs.meta new file mode 100644 index 0000000..cfc4b51 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Mathd.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5f74084b91c74df2839b426c4a381373 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Mathd.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Pool.cs b/Assets/Mirror/Core/Tools/Pool.cs new file mode 100644 index 0000000..f26d49b --- /dev/null +++ b/Assets/Mirror/Core/Tools/Pool.cs @@ -0,0 +1,48 @@ +// Pool to avoid allocations (from libuv2k) +// API consistent with Microsoft's ObjectPool. +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public class Pool + { + // Mirror is single threaded, no need for concurrent collections. + // stack increases the chance that a reused writer remains in cache. + readonly Stack objects = new Stack(); + + // some types might need additional parameters in their constructor, so + // we use a Func generator + readonly Func objectGenerator; + + public Pool(Func objectGenerator, int initialCapacity) + { + this.objectGenerator = objectGenerator; + + // allocate an initial pool so we have fewer (if any) + // allocations in the first few frames (or seconds). + for (int i = 0; i < initialCapacity; ++i) + objects.Push(objectGenerator()); + } + + // take an element from the pool, or create a new one if empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Get() => objects.Count > 0 ? objects.Pop() : objectGenerator(); + + // return an element to the pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(T item) + { + // make sure we can't accidentally insert null values into the pool. + // debugging this would be hard since it would only show on get(). + if (item == null) + throw new ArgumentNullException(nameof(item)); + + objects.Push(item); + } + + // count to see how many objects are in the pool. useful for tests. + public int Count => objects.Count; + } +} diff --git a/Assets/Mirror/Core/Tools/Pool.cs.meta b/Assets/Mirror/Core/Tools/Pool.cs.meta new file mode 100644 index 0000000..1434250 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Pool.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 845bb05fa349344c3811022f4f15dfbc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Pool.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Readme.txt b/Assets/Mirror/Core/Tools/Readme.txt new file mode 100644 index 0000000..09bd920 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Readme.txt @@ -0,0 +1 @@ +Standalone algorithms & structs to help build Mirror. \ No newline at end of file diff --git a/Assets/Mirror/Core/Tools/Readme.txt.meta b/Assets/Mirror/Core/Tools/Readme.txt.meta new file mode 100644 index 0000000..b8d44b0 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: da033671de7d49e0838223a997c56bf1 +timeCreated: 1667486850 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/TimeSample.cs b/Assets/Mirror/Core/Tools/TimeSample.cs new file mode 100644 index 0000000..111e971 --- /dev/null +++ b/Assets/Mirror/Core/Tools/TimeSample.cs @@ -0,0 +1,61 @@ +// TimeSample from Mirror II. +// simple profiling sample, averaged for display in statistics. +// usable in builds without unitiy profiler overhead etc. +// +// .average may safely be called from main thread while Begin/End is in another. +// i.e. worker threads, transport, etc. +using System.Diagnostics; +using System.Threading; + +namespace Mirror +{ + public struct TimeSample + { + // UnityEngine.Time isn't thread safe. use stopwatch instead. + readonly Stopwatch watch; + + // remember when Begin was called + double beginTime; + + // keep accumulating times over the given interval. + // (not readonly. we modify its contents.) + ExponentialMovingAverage ema; + + // average in seconds. + // code often runs in sub-millisecond time. float is more precise. + // + // set with Interlocked for thread safety. + // can be read from main thread while sampling happens in other thread. + public double average; // THREAD SAFE + + // average over N begin/end captures + public TimeSample(int n) + { + watch = new Stopwatch(); + watch.Start(); + ema = new ExponentialMovingAverage(n); + beginTime = 0; + average = 0; + } + + // begin is called before the code to be sampled + public void Begin() + { + // remember when Begin was called. + // keep StopWatch running so we can average over the given interval. + beginTime = watch.Elapsed.TotalSeconds; + // Debug.Log($"Begin @ {beginTime:F4}"); + } + + // end is called after the code to be sampled + public void End() + { + // add duration in seconds to accumulated durations + double elapsed = watch.Elapsed.TotalSeconds - beginTime; + ema.Add(elapsed); + + // expose new average thread safely + Interlocked.Exchange(ref average, ema.Value); + } + } +} diff --git a/Assets/Mirror/Core/Tools/TimeSample.cs.meta b/Assets/Mirror/Core/Tools/TimeSample.cs.meta new file mode 100644 index 0000000..1aad767 --- /dev/null +++ b/Assets/Mirror/Core/Tools/TimeSample.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 26c32f6429554546a88d800c846c74ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/TimeSample.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Utils.cs b/Assets/Mirror/Core/Tools/Utils.cs new file mode 100644 index 0000000..406484f --- /dev/null +++ b/Assets/Mirror/Core/Tools/Utils.cs @@ -0,0 +1,222 @@ +using System; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.SceneManagement; + +namespace Mirror +{ + // Handles network messages on client and server + public delegate void NetworkMessageDelegate(NetworkConnection conn, NetworkReader reader, int channelId); + + // Handles requests to spawn objects on the client + public delegate GameObject SpawnDelegate(Vector3 position, uint assetId); + + public delegate GameObject SpawnHandlerDelegate(SpawnMessage msg); + + // Handles requests to unspawn objects on the client + public delegate void UnSpawnDelegate(GameObject spawned); + + // channels are const ints instead of an enum so people can add their own + // channels (can't extend an enum otherwise). + // + // note that Mirror is slowly moving towards quake style networking which + // will only require reliable for handshake, and unreliable for the rest. + // so eventually we can change this to an Enum and transports shouldn't + // add custom channels anymore. + public static class Channels + { + public const int Reliable = 0; // ordered + public const int Unreliable = 1; // unordered + } + + public static class Utils + { + // detect headless / dedicated server mode + // SystemInfo.graphicsDeviceType is never null in the editor. + // UNITY_SERVER works in builds for all Unity versions 2019 LTS and later. + // For Unity 2019 / 2020, there is no way to detect Server Build checkbox + // state in Build Settings, so they never auto-start headless server / client. + // UNITY_SERVER works in the editor in Unity 2021 LTS and later + // because that's when Dedicated Server platform was added. + // It is intentional for editor play mode to auto-start headless server / client + // when Dedicated Server platform is selected in the editor so that editor + // acts like a headless build to every extent possible for testing / debugging. + public static bool IsHeadless() => +#if UNITY_SERVER + true; +#else + SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null; +#endif + + // detect WebGL mode + public const bool IsWebGL = +#if UNITY_WEBGL + true; +#else + false; +#endif + + // detect Debug mode + public const bool IsDebug = +#if DEBUG + true; +#else + false; +#endif + + public static uint GetTrueRandomUInt() + { + // use Crypto RNG to avoid having time based duplicates + using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) + { + byte[] bytes = new byte[4]; + rng.GetBytes(bytes); + return BitConverter.ToUInt32(bytes, 0); + } + } + + public static bool IsPrefab(GameObject obj) + { +#if UNITY_EDITOR + return UnityEditor.PrefabUtility.IsPartOfPrefabAsset(obj); +#else + return false; +#endif + } + + // simplified IsSceneObject check from Mirror II + public static bool IsSceneObject(NetworkIdentity identity) + { + // original UNET / Mirror still had the IsPersistent check. + // it never fires though. even for Prefabs dragged to the Scene. + // (see Scene Objects example scene.) + // #if UNITY_EDITOR + // if (UnityEditor.EditorUtility.IsPersistent(identity.gameObject)) + // return false; + // #endif + + return identity.gameObject.hideFlags != HideFlags.NotEditable && + identity.gameObject.hideFlags != HideFlags.HideAndDontSave && + identity.sceneId != 0; + } + + public static bool IsSceneObjectWithPrefabParent(GameObject gameObject, out GameObject prefab) + { + prefab = null; + +#if UNITY_EDITOR + if (!UnityEditor.PrefabUtility.IsPartOfPrefabInstance(gameObject)) + { + return false; + } + prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(gameObject); +#endif + + if (prefab == null) + { + Debug.LogError($"Failed to find prefab parent for scene object [name:{gameObject.name}]"); + return false; + } + return true; + } + + // is a 2D point in screen? (from ummorpg) + // (if width = 1024, then indices from 0..1023 are valid (=1024 indices) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsPointInScreen(Vector2 point) => + 0 <= point.x && point.x < Screen.width && + 0 <= point.y && point.y < Screen.height; + + // pretty print bytes as KB/MB/GB/etc. from DOTSNET + // long to support > 2GB + // divides by floats to return "2.5MB" etc. + public static string PrettyBytes(long bytes) + { + // bytes + if (bytes < 1024) + return $"{bytes} B"; + // kilobytes + else if (bytes < 1024L * 1024L) + return $"{(bytes / 1024f):F2} KB"; + // megabytes + else if (bytes < 1024 * 1024L * 1024L) + return $"{(bytes / (1024f * 1024f)):F2} MB"; + // gigabytes + return $"{(bytes / (1024f * 1024f * 1024f)):F2} GB"; + } + + // pretty print seconds as hours:minutes:seconds(.milliseconds/100)s. + // double for long running servers. + public static string PrettySeconds(double seconds) + { + TimeSpan t = TimeSpan.FromSeconds(seconds); + string res = ""; + if (t.Days > 0) res += $"{t.Days}d"; + if (t.Hours > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Hours}h"; + if (t.Minutes > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Minutes}m"; + // 0.5s, 1.5s etc. if any milliseconds. 1s, 2s etc. if any seconds + if (t.Milliseconds > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Seconds}.{(t.Milliseconds / 100)}s"; + else if (t.Seconds > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Seconds}s"; + // if the string is still empty because the value was '0', then at least + // return the seconds instead of returning an empty string + return res != "" ? res : "0s"; + } + + // universal .spawned function + public static NetworkIdentity GetSpawnedInServerOrClient(uint netId) + { + // server / host mode: use the one from server. + // host mode has access to all spawned. + if (NetworkServer.active) + { + NetworkServer.spawned.TryGetValue(netId, out NetworkIdentity entry); + return entry; + } + + // client + if (NetworkClient.active) + { + NetworkClient.spawned.TryGetValue(netId, out NetworkIdentity entry); + return entry; + } + + return null; + } + + // keep a GUI window in screen. + // for example. if it's at x=1000 and screen is resized to w=500, + // it won't get lost in the invisible area etc. + public static Rect KeepInScreen(Rect rect) + { + // ensure min + rect.x = Math.Max(rect.x, 0); + rect.y = Math.Max(rect.y, 0); + + // ensure max + rect.x = Math.Min(rect.x, Screen.width - rect.width); + rect.y = Math.Min(rect.y, Screen.width - rect.height); + + return rect; + } + + // create local connections pair and connect them + public static void CreateLocalConnections( + out LocalConnectionToClient connectionToClient, + out LocalConnectionToServer connectionToServer) + { + connectionToServer = new LocalConnectionToServer(); + connectionToClient = new LocalConnectionToClient(); + connectionToServer.connectionToClient = connectionToClient; + connectionToClient.connectionToServer = connectionToServer; + } + + public static bool IsSceneActive(string scene) + { + Scene activeScene = SceneManager.GetActiveScene(); + return activeScene.path == scene || + activeScene.name == scene; + } + } +} diff --git a/Assets/Mirror/Core/Tools/Utils.cs.meta b/Assets/Mirror/Core/Tools/Utils.cs.meta new file mode 100644 index 0000000..aa65c05 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Utils.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b530ce39098b54374a29ad308c8e4554 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Utils.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Vector3Long.cs b/Assets/Mirror/Core/Tools/Vector3Long.cs new file mode 100644 index 0000000..d54a46c --- /dev/null +++ b/Assets/Mirror/Core/Tools/Vector3Long.cs @@ -0,0 +1,125 @@ +#pragma warning disable CS0659 // 'Vector3Long' overrides Object.Equals(object o) but does not override Object.GetHashCode() +#pragma warning disable CS0661 // 'Vector3Long' defines operator == or operator != but does not override Object.GetHashCode() + +// Vector3Long by mischa (based on game engine project) +using System; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public struct Vector3Long + { + public long x; + public long y; + public long z; + + public static readonly Vector3Long zero = new Vector3Long(0, 0, 0); + public static readonly Vector3Long one = new Vector3Long(1, 1, 1); + public static readonly Vector3Long forward = new Vector3Long(0, 0, 1); + public static readonly Vector3Long back = new Vector3Long(0, 0, -1); + public static readonly Vector3Long left = new Vector3Long(-1, 0, 0); + public static readonly Vector3Long right = new Vector3Long(1, 0, 0); + public static readonly Vector3Long up = new Vector3Long(0, 1, 0); + public static readonly Vector3Long down = new Vector3Long(0, -1, 0); + + // constructor ///////////////////////////////////////////////////////// + public Vector3Long(long x, long y, long z) + { + this.x = x; + this.y = y; + this.z = z; + } + + // operators /////////////////////////////////////////////////////////// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long operator +(Vector3Long a, Vector3Long b) => + new Vector3Long(a.x + b.x, a.y + b.y, a.z + b.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long operator -(Vector3Long a, Vector3Long b) => + new Vector3Long(a.x - b.x, a.y - b.y, a.z - b.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long operator -(Vector3Long v) => + new Vector3Long(-v.x, -v.y, -v.z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long operator *(Vector3Long a, long n) => + new Vector3Long(a.x * n, a.y * n, a.z * n); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3Long operator *(long n, Vector3Long a) => + new Vector3Long(a.x * n, a.y * n, a.z * n); + + // == returns true if approximately equal (with epsilon). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector3Long a, Vector3Long b) => + a.x == b.x && + a.y == b.y && + a.z == b.z; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector3Long a, Vector3Long b) => !(a == b); + + // NO IMPLICIT System.Numerics.Vector3Long conversion because double<->float + // would silently lose precision in large worlds. + + // [i] component index. useful for iterating all components etc. + public long this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + default: throw new IndexOutOfRangeException($"Vector3Long[{index}] out of range."); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + case 2: + z = value; + break; + default: throw new IndexOutOfRangeException($"Vector3Long[{index}] out of range."); + } + } + } + + // instance functions ////////////////////////////////////////////////// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() => $"({x} {y} {z})"; + + // equality //////////////////////////////////////////////////////////// + // implement Equals & HashCode explicitly for performance. + // calling .Equals (instead of "==") checks for exact equality. + // (API compatibility) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Vector3Long other) => + x == other.x && y == other.y && z == other.z; + + // Equals(object) can reuse Equals(Vector4) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object other) => + other is Vector3Long vector4 && Equals(vector4); + +#if UNITY_2021_3_OR_NEWER + // Unity 2019/2020 don't have HashCode.Combine yet. + // this is only to avoid reflection. without defining, it works too. + // default generated by rider + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(x, y, z); +#endif + } +} diff --git a/Assets/Mirror/Core/Tools/Vector3Long.cs.meta b/Assets/Mirror/Core/Tools/Vector3Long.cs.meta new file mode 100644 index 0000000..68e89d5 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Vector3Long.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 18efa4e349254185ad257401dd24628b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Vector3Long.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Tools/Vector4Long.cs b/Assets/Mirror/Core/Tools/Vector4Long.cs new file mode 100644 index 0000000..0eba99a --- /dev/null +++ b/Assets/Mirror/Core/Tools/Vector4Long.cs @@ -0,0 +1,126 @@ +#pragma warning disable CS0659 // 'Vector4Long' overrides Object.Equals(object o) but does not override Object.GetHashCode() +#pragma warning disable CS0661 // 'Vector4Long' defines operator == or operator != but does not override Object.GetHashCode() + +// Vector4Long by mischa (based on game engine project) +using System; +using System.Runtime.CompilerServices; + +namespace Mirror +{ + public struct Vector4Long + { + public long x; + public long y; + public long z; + public long w; + + public static readonly Vector4Long zero = new Vector4Long(0, 0, 0, 0); + public static readonly Vector4Long one = new Vector4Long(1, 1, 1, 1); + + // constructor ///////////////////////////////////////////////////////// + public Vector4Long(long x, long y, long z, long w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + // operators /////////////////////////////////////////////////////////// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long operator +(Vector4Long a, Vector4Long b) => + new Vector4Long(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long operator -(Vector4Long a, Vector4Long b) => + new Vector4Long(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long operator -(Vector4Long v) => + new Vector4Long(-v.x, -v.y, -v.z, -v.w); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long operator *(Vector4Long a, long n) => + new Vector4Long(a.x * n, a.y * n, a.z * n, a.w * n); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4Long operator *(long n, Vector4Long a) => + new Vector4Long(a.x * n, a.y * n, a.z * n, a.w * n); + + // == returns true if approximately equal (with epsilon). + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector4Long a, Vector4Long b) => + a.x == b.x && + a.y == b.y && + a.z == b.z && + a.w == b.w; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector4Long a, Vector4Long b) => !(a == b); + + // NO IMPLICIT System.Numerics.Vector4Long conversion because double<->float + // would silently lose precision in large worlds. + + // [i] component index. useful for iterating all components etc. + public long this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + switch (index) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: throw new IndexOutOfRangeException($"Vector4Long[{index}] out of range."); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + case 2: + z = value; + break; + case 3: + w = value; + break; + default: throw new IndexOutOfRangeException($"Vector4Long[{index}] out of range."); + } + } + } + + // instance functions ////////////////////////////////////////////////// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() => $"({x} {y} {z} {w})"; + + // equality //////////////////////////////////////////////////////////// + // implement Equals & HashCode explicitly for performance. + // calling .Equals (instead of "==") checks for exact equality. + // (API compatibility) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Vector4Long other) => + x == other.x && y == other.y && z == other.z && w == other.w; + + // Equals(object) can reuse Equals(Vector4) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object other) => + other is Vector4Long vector4 && Equals(vector4); + +#if UNITY_2021_3_OR_NEWER + // Unity 2019/2020 don't have HashCode.Combine yet. + // this is only to avoid reflection. without defining, it works too. + // default generated by rider + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => HashCode.Combine(x, y, z, w); +#endif + } +} diff --git a/Assets/Mirror/Core/Tools/Vector4Long.cs.meta b/Assets/Mirror/Core/Tools/Vector4Long.cs.meta new file mode 100644 index 0000000..b6ed4d8 --- /dev/null +++ b/Assets/Mirror/Core/Tools/Vector4Long.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9f69bf6b6d73476ab3f31dd635bb6497 +timeCreated: 1726777293 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Tools/Vector4Long.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/Transport.cs b/Assets/Mirror/Core/Transport.cs new file mode 100644 index 0000000..926a5c0 --- /dev/null +++ b/Assets/Mirror/Core/Transport.cs @@ -0,0 +1,210 @@ +// For future reference, here is what Transports need to do in Mirror: +// +// Connecting: +// * Transports are responsible to call either OnConnected || OnDisconnected +// in a certain time after a Connect was called. It can not end in limbo. +// +// Disconnecting: +// * Connections might disconnect voluntarily by the other end. +// * Connections might be disconnect involuntarily by the server. +// * Either way, Transports need to detect it and call OnDisconnected. +// +// Timeouts: +// * Transports should expose a configurable timeout +// * Transports are responsible for calling OnDisconnected after a timeout +// +// Channels: +// * Default channel is Reliable, as in reliable ordered (OR DISCONNECT) +// * Where possible, Unreliable should be supported (unordered, no guarantee) +// +// Other: +// * Transports functions are all bound to the main thread. +// (Transports can use other threads in the background if they manage them) +// * Transports should only process messages while the component is enabled. +// +using System; +using UnityEngine; + +namespace Mirror +{ + /// Abstract transport layer component + public abstract class Transport : MonoBehaviour + { + /// The current transport used by Mirror. + public static Transport active; + + /// Is this transport available in the current platform? + public abstract bool Available(); + + /// Is this transport encrypted for secure communication? + public virtual bool IsEncrypted => false; + + /// If encrypted, which cipher is used? + public virtual string EncryptionCipher => ""; + + // client ////////////////////////////////////////////////////////////// + /// Called by Transport when the client connected to the server. + public Action OnClientConnected; + + /// Called by Transport when the client received a message from the server. + public Action, int> OnClientDataReceived; + + /// Called by Transport when the client sent a message to the server. + // Transports are responsible for calling it because: + // - groups it together with OnReceived responsibility + // - allows transports to decide if anything was sent or not + // - allows transports to decide the actual used channel (i.e. tcp always sending reliable) + public Action, int> OnClientDataSent; + + /// Called by Transport when the client encountered an error. + public Action OnClientError; + + /// Called by Transport when the client encountered an error. + public Action OnClientTransportException; + + /// Called by Transport when the client disconnected from the server. + public Action OnClientDisconnected; + + // server ////////////////////////////////////////////////////////////// + + // Deprecated 2024-07-20 + [Obsolete("Use OnServerConnectedWithAddress and pass the remote client address instead")] + public Action OnServerConnected; + + /// Called by Transport when a new client connected to the server. + public Action OnServerConnectedWithAddress; + + /// Called by Transport when the server received a message from a client. + public Action, int> OnServerDataReceived; + + /// Called by Transport when the server sent a message to a client. + // Transports are responsible for calling it because: + // - groups it together with OnReceived responsibility + // - allows transports to decide if anything was sent or not + // - allows transports to decide the actual used channel (i.e. tcp always sending reliable) + public Action, int> OnServerDataSent; + + /// Called by Transport when a server's connection encountered a problem. + /// If a Disconnect will also be raised, raise the Error first. + public Action OnServerError; + + /// Called by Transport when a server's connection encountered a problem. + /// If a Disconnect will also be raised, raise the Error first. + public Action OnServerTransportException; + + /// Called by Transport when a client disconnected from the server. + public Action OnServerDisconnected; + + // client functions //////////////////////////////////////////////////// + /// True if the client is currently connected to the server. + public abstract bool ClientConnected(); + + /// Connects the client to the server at the address. + public abstract void ClientConnect(string address); + + /// Connects the client to the server at the Uri. + public virtual void ClientConnect(Uri uri) + { + // By default, to keep backwards compatibility, just connect to the host + // in the uri + ClientConnect(uri.Host); + } + + /// Sends a message to the server over the given channel. + // The ArraySegment is only valid until returning. Copy if needed. + public abstract void ClientSend(ArraySegment segment, int channelId = Channels.Reliable); + + /// Disconnects the client from the server + public abstract void ClientDisconnect(); + + // server functions //////////////////////////////////////////////////// + /// Returns server address as Uri. + // Useful for NetworkDiscovery. + public abstract Uri ServerUri(); + + /// True if the server is currently listening for connections. + public abstract bool ServerActive(); + + /// Start listening for connections. + public abstract void ServerStart(); + + /// Send a message to a client over the given channel. + public abstract void ServerSend(int connectionId, ArraySegment segment, int channelId = Channels.Reliable); + + /// Disconnect a client from the server. + public abstract void ServerDisconnect(int connectionId); + + /// Get a client's address on the server. + // Can be useful for Game Master IP bans etc. + public abstract string ServerGetClientAddress(int connectionId); + + /// Stop listening and disconnect all connections. + public abstract void ServerStop(); + + /// Maximum message size for the given channel. + // Different channels often have different sizes, ranging from MTU to + // several megabytes. + // + // Needs to return a value at all times, even if the Transport isn't + // running or available because it's needed for initializations. + public abstract int GetMaxPacketSize(int channelId = Channels.Reliable); + + /// Recommended Batching threshold for this transport. + // Uses GetMaxPacketSize by default. + // Some transports like kcp support large max packet sizes which should + // not be used for batching all the time because they end up being too + // slow (head of line blocking etc.). + public virtual int GetBatchThreshold(int channelId = Channels.Reliable) + { + return GetMaxPacketSize(channelId); + } + + // block Update & LateUpdate to show warnings if Transports still use + // them instead of using + // Client/ServerEarlyUpdate: to process incoming messages + // Client/ServerLateUpdate: to process outgoing messages + // those are called by NetworkClient/Server at the right time. + // + // allows transports to implement the proper network update order of: + // process_incoming() + // update_world() + // process_outgoing() + // + // => see NetworkLoop.cs for detailed explanations! +#pragma warning disable UNT0001 // Empty Unity message + public void Update() {} + public void LateUpdate() {} +#pragma warning restore UNT0001 // Empty Unity message + + /// + /// NetworkLoop NetworkEarly/LateUpdate were added for a proper network + /// update order. the goal is to: + /// process_incoming() + /// update_world() + /// process_outgoing() + /// in order to avoid unnecessary latency and data races. + /// + // => split into client and server parts so that we can cleanly call + // them from NetworkClient/Server + // => VIRTUAL for now so we can take our time to convert transports + // without breaking anything. + public virtual void ClientEarlyUpdate() {} + public virtual void ServerEarlyUpdate() {} + public virtual void ClientLateUpdate() {} + public virtual void ServerLateUpdate() {} + + /// Shut down the transport, both as client and server + public abstract void Shutdown(); + + /// Called by Unity when quitting. Inheriting Transports should call base for proper Shutdown. + // (this can't be in OnDestroy: https://github.com/MirrorNetworking/Mirror/issues/3952) + public virtual void OnApplicationQuit() + { + // stop transport (e.g. to shut down threads) + // (when pressing Stop in the Editor, Unity keeps threads alive + // until we press Start again. so if Transports use threads, we + // really want them to end now and not after next start) + Shutdown(); + } + } +} diff --git a/Assets/Mirror/Core/Transport.cs.meta b/Assets/Mirror/Core/Transport.cs.meta new file mode 100644 index 0000000..4931067 --- /dev/null +++ b/Assets/Mirror/Core/Transport.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cfffcac25d6d64ced9de620159e221b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/Transport.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/TransportError.cs b/Assets/Mirror/Core/TransportError.cs new file mode 100644 index 0000000..b452015 --- /dev/null +++ b/Assets/Mirror/Core/TransportError.cs @@ -0,0 +1,17 @@ +// Mirror transport error code enum. +// most transport implementations should use a subset of this, +// and then translate the transport error codes to mirror error codes. +namespace Mirror +{ + public enum TransportError : byte + { + DnsResolve, // failed to resolve a host name + Refused, // connection refused by other end. server full etc. + Timeout, // ping timeout or dead link + Congestion, // more messages than transport / network can process + InvalidReceive, // recv invalid packet (possibly intentional attack) + InvalidSend, // user tried to send invalid data + ConnectionClosed, // connection closed voluntarily or lost involuntarily + Unexpected // unexpected error / exception, requires fix. + } +} diff --git a/Assets/Mirror/Core/TransportError.cs.meta b/Assets/Mirror/Core/TransportError.cs.meta new file mode 100644 index 0000000..1b56a9b --- /dev/null +++ b/Assets/Mirror/Core/TransportError.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ce162bdedd704db9b8c35d163f0c1d54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/TransportError.cs + uploadId: 736421 diff --git a/Assets/Mirror/Core/WeaverFuse.cs b/Assets/Mirror/Core/WeaverFuse.cs new file mode 100644 index 0000000..f850323 --- /dev/null +++ b/Assets/Mirror/Core/WeaverFuse.cs @@ -0,0 +1,22 @@ +// safety fuse for weaver to flip. +// runtime can check this to ensure weaving succeded. +// otherwise running server/client would give lots of random 'writer not found' etc. errors. +// this is much cleaner. +// +// note that ILPostProcessor errors already block entering playmode. +// however, issues could still stop the weaving from running at all. +// WeaverFuse can check if it actually ran. +namespace Mirror +{ + public static class WeaverFuse + { + // this trick only works for ILPostProcessor. + // CompilationFinishedHook can't weaver Mirror.dll. + public static bool Weaved() => +#if UNITY_2020_3_OR_NEWER + false; +#else + true; +#endif + } +} diff --git a/Assets/Mirror/Core/WeaverFuse.cs.meta b/Assets/Mirror/Core/WeaverFuse.cs.meta new file mode 100644 index 0000000..b4572a5 --- /dev/null +++ b/Assets/Mirror/Core/WeaverFuse.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4de3dfbcbd2e41fcac947c04bcac52c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Core/WeaverFuse.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor.meta b/Assets/Mirror/Editor.meta new file mode 100644 index 0000000..f679511 --- /dev/null +++ b/Assets/Mirror/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2539267b6934a4026a505690a1e1eda2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/AndroidManifestHelper.cs b/Assets/Mirror/Editor/AndroidManifestHelper.cs new file mode 100644 index 0000000..bae0082 --- /dev/null +++ b/Assets/Mirror/Editor/AndroidManifestHelper.cs @@ -0,0 +1,116 @@ +// Android NetworkDiscovery Multicast fix +// https://github.com/vis2k/Mirror/pull/2887 +using UnityEditor; +using UnityEngine; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using System.Xml; +using System.IO; +#if UNITY_ANDROID +using UnityEditor.Android; +#endif + +namespace Mirror +{ + [InitializeOnLoad] + public class AndroidManifestHelper : IPreprocessBuildWithReport, IPostprocessBuildWithReport + #if UNITY_ANDROID + , IPostGenerateGradleAndroidProject + #endif + { + public int callbackOrder { get { return 99999; } } + + #if UNITY_ANDROID + public void OnPostGenerateGradleAndroidProject(string path) + { + string manifestFolder = Path.Combine(path, "src/main"); + string sourceFile = manifestFolder + "/AndroidManifest.xml"; + // Load android manifest file + XmlDocument doc = new XmlDocument(); + doc.Load(sourceFile); + + string androidNamespaceURI; + XmlElement element = (XmlElement)doc.SelectSingleNode("/manifest"); + if (element == null) + { + UnityEngine.Debug.LogError("Could not find manifest tag in android manifest."); + return; + } + + // Get android namespace URI from the manifest + androidNamespaceURI = element.GetAttribute("xmlns:android"); + if (string.IsNullOrEmpty(androidNamespaceURI)) + { + UnityEngine.Debug.LogError("Could not find Android Namespace in manifest."); + return; + } + AddOrRemoveTag(doc, + androidNamespaceURI, + "/manifest", + "uses-permission", + "android.permission.CHANGE_WIFI_MULTICAST_STATE", + true, + false); + AddOrRemoveTag(doc, + androidNamespaceURI, + "/manifest", + "uses-permission", + "android.permission.INTERNET", + true, + false); + doc.Save(sourceFile); + } + #endif + + static void AddOrRemoveTag(XmlDocument doc, string @namespace, string path, string elementName, string name, bool required, bool modifyIfFound, params string[] attrs) // name, value pairs + { + var nodes = doc.SelectNodes(path + "/" + elementName); + XmlElement element = null; + foreach (XmlElement e in nodes) + { + if (name == null || name == e.GetAttribute("name", @namespace)) + { + element = e; + break; + } + } + + if (required) + { + if (element == null) + { + var parent = doc.SelectSingleNode(path); + element = doc.CreateElement(elementName); + element.SetAttribute("name", @namespace, name); + parent.AppendChild(element); + } + + for (int i = 0; i < attrs.Length; i += 2) + { + if (modifyIfFound || string.IsNullOrEmpty(element.GetAttribute(attrs[i], @namespace))) + { + if (attrs[i + 1] != null) + { + element.SetAttribute(attrs[i], @namespace, attrs[i + 1]); + } + else + { + element.RemoveAttribute(attrs[i], @namespace); + } + } + } + } + else + { + if (element != null && modifyIfFound) + { + element.ParentNode.RemoveChild(element); + } + } + } + + public void OnPostprocessBuild(BuildReport report) {} + public void OnPreprocessBuild(BuildReport report) {} + } +} + diff --git a/Assets/Mirror/Editor/AndroidManifestHelper.cs.meta b/Assets/Mirror/Editor/AndroidManifestHelper.cs.meta new file mode 100644 index 0000000..996e3e9 --- /dev/null +++ b/Assets/Mirror/Editor/AndroidManifestHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 80cc70189403d7444bbffd185ca28462 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/AndroidManifestHelper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/EditorHelper.cs b/Assets/Mirror/Editor/EditorHelper.cs new file mode 100644 index 0000000..c3551ab --- /dev/null +++ b/Assets/Mirror/Editor/EditorHelper.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + public static class EditorHelper + { + public static string FindPath() + { + string typeName = typeof(T).Name; + + string[] guidsFound = AssetDatabase.FindAssets($"t:Script {typeName}"); + if (guidsFound.Length >= 1 && !string.IsNullOrWhiteSpace(guidsFound[0])) + { + if (guidsFound.Length > 1) + { + Debug.LogWarning($"Found more than one{typeName}"); + } + + string path = AssetDatabase.GUIDToAssetPath(guidsFound[0]); + return Path.GetDirectoryName(path); + } + else + { + Debug.LogError($"Could not find path of {typeName}"); + return string.Empty; + } + } + + + public static IEnumerable IterateOverProject(string filter) + { + foreach (string guid in AssetDatabase.FindAssets(filter)) + { + yield return AssetDatabase.GUIDToAssetPath(guid); + } + } + } +} diff --git a/Assets/Mirror/Editor/EditorHelper.cs.meta b/Assets/Mirror/Editor/EditorHelper.cs.meta new file mode 100644 index 0000000..c2a4577 --- /dev/null +++ b/Assets/Mirror/Editor/EditorHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: dba787f167ff29c4288532af1ec3584c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/EditorHelper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Icon.meta b/Assets/Mirror/Editor/Icon.meta new file mode 100644 index 0000000..7338187 --- /dev/null +++ b/Assets/Mirror/Editor/Icon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5f1356ad059a1243910a4e82cd68c5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/Icon/MirrorIcon.png b/Assets/Mirror/Editor/Icon/MirrorIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..1be896157a63edfe96735948eeb145381697d551 GIT binary patch literal 138247 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 b}aI>P^u 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 all public and private fields for a type + // deepestBaseType: Stops at this base type (exclusive) + public static IEnumerable GetAllFields(Type type, Type deepestBaseType) + { + const BindingFlags publicFields = BindingFlags.Public | BindingFlags.Instance; + const BindingFlags privateFields = BindingFlags.NonPublic | BindingFlags.Instance; + + // get public fields (includes fields from base type) + FieldInfo[] allPublicFields = type.GetFields(publicFields); + foreach (FieldInfo field in allPublicFields) + { + yield return field; + } + + // get private fields in current type, then move to base type + while (type != null) + { + FieldInfo[] allPrivateFields = type.GetFields(privateFields); + foreach (FieldInfo field in allPrivateFields) + { + yield return field; + } + + type = type.BaseType; + + // stop early + if (type == deepestBaseType) + { + break; + } + } + } + + public static bool IsSyncVar(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(SyncVarAttribute), true); + return fieldMarkers.Length > 0; + } + + public static bool IsSerializeField(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(SerializeField), true); + return fieldMarkers.Length > 0; + } + + public static bool IsVisibleField(this FieldInfo field) + { + return field.IsPublic || IsSerializeField(field); + } + + public static bool ImplementsInterface(this FieldInfo field) + { + return typeof(T).IsAssignableFrom(field.FieldType); + } + + public static bool HasShowInInspector(this FieldInfo field) + { + object[] fieldMarkers = field.GetCustomAttributes(typeof(ShowInInspectorAttribute), true); + return fieldMarkers.Length > 0; + } + + // checks if SyncObject is public or has our custom [ShowInInspector] field + public static bool IsVisibleSyncObject(this FieldInfo field) + { + return field.IsPublic || HasShowInInspector(field); + } + } +} diff --git a/Assets/Mirror/Editor/InspectorHelper.cs.meta b/Assets/Mirror/Editor/InspectorHelper.cs.meta new file mode 100644 index 0000000..91205ff --- /dev/null +++ b/Assets/Mirror/Editor/InspectorHelper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 047c894c2a5ccc1438b7e59302f62744 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/InspectorHelper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/LagCompensatorInspector.cs b/Assets/Mirror/Editor/LagCompensatorInspector.cs new file mode 100644 index 0000000..f706384 --- /dev/null +++ b/Assets/Mirror/Editor/LagCompensatorInspector.cs @@ -0,0 +1,14 @@ +using UnityEditor; + +namespace Mirror +{ + [CustomEditor(typeof(LagCompensator))] + public class LagCompensatorInspector : Editor + { + public override void OnInspectorGUI() + { + EditorGUILayout.HelpBox("Preview Component - Feedback appreciated on GitHub or Discord!", MessageType.Warning); + DrawDefaultInspector(); + } + } +} diff --git a/Assets/Mirror/Editor/LagCompensatorInspector.cs.meta b/Assets/Mirror/Editor/LagCompensatorInspector.cs.meta new file mode 100644 index 0000000..0dba2ed --- /dev/null +++ b/Assets/Mirror/Editor/LagCompensatorInspector.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 703e39b5385ae2e479987ff4ec0707a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/LagCompensatorInspector.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef b/Assets/Mirror/Editor/Mirror.Editor.asmdef new file mode 100644 index 0000000..800e67b --- /dev/null +++ b/Assets/Mirror/Editor/Mirror.Editor.asmdef @@ -0,0 +1,20 @@ +{ + "name": "Mirror.Editor", + "rootNamespace": "", + "references": [ + "GUID:30817c1a0e6d646d99c048fc403f5979", + "GUID:72872094b21c16e48b631b2224833d49", + "GUID:1d0b9d21c3ff546a4aa32399dfd33474" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta b/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta new file mode 100644 index 0000000..2d148c7 --- /dev/null +++ b/Assets/Mirror/Editor/Mirror.Editor.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 1c7c33eb5480dd24c9e29a8250c1a775 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Mirror.Editor.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs new file mode 100644 index 0000000..52c56d6 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs @@ -0,0 +1,104 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomEditor(typeof(NetworkBehaviour), true)] + [CanEditMultipleObjects] + public class NetworkBehaviourInspector : Editor + { + bool syncsAnything; + SyncObjectCollectionsDrawer syncObjectCollectionsDrawer; + + // does this type sync anything? otherwise we don't need to show syncInterval + bool SyncsAnything(Type scriptClass) + { + // check for all SyncVar fields, they don't have to be visible + foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) + { + if (field.IsSyncVar()) + { + return true; + } + } + + // has OnSerialize that is not in NetworkBehaviour? + // then it either has a syncvar or custom OnSerialize. either way + // this means we have something to sync. + MethodInfo method = scriptClass.GetMethod("OnSerialize"); + if (method != null && method.DeclaringType != typeof(NetworkBehaviour)) + { + return true; + } + + // SyncObjects are serialized in NetworkBehaviour.OnSerialize, which + // is always there even if we don't use SyncObjects. so we need to + // search for SyncObjects manually. + // Any SyncObject should be added to syncObjects when unity creates an + // object so we can check length of list so see if sync objects exists + return ((NetworkBehaviour)serializedObject.targetObject).HasSyncObjects(); + } + + void OnEnable() + { + // sometimes target is null. just return early. + if (target == null) return; + + // If target's base class is changed from NetworkBehaviour to MonoBehaviour + // then Unity temporarily keep using this Inspector causing things to break + if (!(target is NetworkBehaviour)) { return; } + + Type scriptClass = target.GetType(); + + syncObjectCollectionsDrawer = new SyncObjectCollectionsDrawer(serializedObject.targetObject); + + syncsAnything = SyncsAnything(scriptClass); + } + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + DrawSyncObjectCollections(); + DrawDefaultSyncSettings(); + } + + // Draws Sync Objects that are IEnumerable + protected void DrawSyncObjectCollections() + { + // Need this check in case OnEnable returns early + if (syncObjectCollectionsDrawer == null) return; + + syncObjectCollectionsDrawer.Draw(); + } + + // Draws SyncSettings if the NetworkBehaviour has anything to sync + protected void DrawDefaultSyncSettings() + { + // does it sync anything? then show extra properties + // (no need to show it if the class only has Cmds/Rpcs and no sync) + if (!syncsAnything) + { + return; + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Sync Settings", EditorStyles.boldLabel); + + // sync direction + SerializedProperty syncDirection = serializedObject.FindProperty("syncDirection"); + EditorGUILayout.PropertyField(syncDirection); + + // sync mdoe: only show for ServerToClient components + if (syncDirection.enumValueIndex == (int)SyncDirection.ServerToClient) + EditorGUILayout.PropertyField(serializedObject.FindProperty("syncMode")); + + // sync interval + EditorGUILayout.PropertyField(serializedObject.FindProperty("syncInterval")); + + // apply + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta new file mode 100644 index 0000000..428f07d --- /dev/null +++ b/Assets/Mirror/Editor/NetworkBehaviourInspector.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f02853db46b6346e4866594a96c3b0e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/NetworkBehaviourInspector.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs b/Assets/Mirror/Editor/NetworkInformationPreview.cs new file mode 100644 index 0000000..b4dbe5e --- /dev/null +++ b/Assets/Mirror/Editor/NetworkInformationPreview.cs @@ -0,0 +1,307 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPreview(typeof(GameObject))] + class NetworkInformationPreview : ObjectPreview + { + struct NetworkIdentityInfo + { + public GUIContent name; + public GUIContent value; + } + + struct NetworkBehaviourInfo + { + // This is here just so we can check if it's enabled/disabled + public NetworkBehaviour behaviour; + public GUIContent name; + } + + class Styles + { + public GUIStyle labelStyle = new GUIStyle(EditorStyles.label); + public GUIStyle componentName = new GUIStyle(EditorStyles.boldLabel); + public GUIStyle disabledName = new GUIStyle(EditorStyles.miniLabel); + + public Styles() + { + Color fontColor = new Color(0.7f, 0.7f, 0.7f); + labelStyle.padding.right += 20; + labelStyle.normal.textColor = fontColor; + labelStyle.active.textColor = fontColor; + labelStyle.focused.textColor = fontColor; + labelStyle.hover.textColor = fontColor; + labelStyle.onNormal.textColor = fontColor; + labelStyle.onActive.textColor = fontColor; + labelStyle.onFocused.textColor = fontColor; + labelStyle.onHover.textColor = fontColor; + + componentName.normal.textColor = fontColor; + componentName.active.textColor = fontColor; + componentName.focused.textColor = fontColor; + componentName.hover.textColor = fontColor; + componentName.onNormal.textColor = fontColor; + componentName.onActive.textColor = fontColor; + componentName.onFocused.textColor = fontColor; + componentName.onHover.textColor = fontColor; + + disabledName.normal.textColor = fontColor; + disabledName.active.textColor = fontColor; + disabledName.focused.textColor = fontColor; + disabledName.hover.textColor = fontColor; + disabledName.onNormal.textColor = fontColor; + disabledName.onActive.textColor = fontColor; + disabledName.onFocused.textColor = fontColor; + disabledName.onHover.textColor = fontColor; + } + } + + GUIContent title; + Styles styles = new Styles(); + + public override GUIContent GetPreviewTitle() + { + if (title == null) + { + title = new GUIContent("Network Information"); + } + return title; + } + + public override bool HasPreviewGUI() + { + // need to check if target is null to stop MissingReferenceException + return target != null && target is GameObject gameObject && gameObject.GetComponent() != null; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + if (Event.current.type != EventType.Repaint) + return; + + if (target == null) + return; + + GameObject targetGameObject = target as GameObject; + + if (targetGameObject == null) + return; + + NetworkIdentity identity = targetGameObject.GetComponent(); + + if (identity == null) + return; + + if (styles == null) + styles = new Styles(); + + + // padding + RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); + Rect paddedr = previewPadding.Add(r); + + //Centering + float initialX = paddedr.x + 10; + float Y = paddedr.y + 10; + + Y = DrawNetworkIdentityInfo(identity, initialX, Y); + + Y = DrawNetworkBehaviors(identity, initialX, Y); + + Y = DrawObservers(identity, initialX, Y); + + _ = DrawOwner(identity, initialX, Y); + + } + + float DrawNetworkIdentityInfo(NetworkIdentity identity, float initialX, float Y) + { + IEnumerable infos = GetNetworkIdentityInfo(identity); + // Get required label size for the names of the information values we're going to show + // There are two columns, one with label for the name of the info and the next for the value + Vector2 maxNameLabelSize = new Vector2(140, 16); + Vector2 maxValueLabelSize = GetMaxNameLabelSize(infos); + + Rect labelRect = new Rect(initialX, Y, maxNameLabelSize.x, maxNameLabelSize.y); + + // height needs a +1 to line up nicely + Rect idLabelRect = new Rect(maxNameLabelSize.x, Y, maxValueLabelSize.x, maxValueLabelSize.y + 1); + + foreach (NetworkIdentityInfo info in infos) + { + GUI.Label(labelRect, info.name, styles.labelStyle); + GUI.Label(idLabelRect, info.value, styles.componentName); + labelRect.y += labelRect.height; + labelRect.x = initialX; + idLabelRect.y += idLabelRect.height; + } + + return labelRect.y; + } + + float DrawNetworkBehaviors(NetworkIdentity identity, float initialX, float Y) + { + IEnumerable behavioursInfo = GetNetworkBehaviorInfo(identity); + + // Show behaviours list in a different way than the name/value pairs above + Vector2 maxBehaviourLabelSize = GetMaxBehaviourLabelSize(behavioursInfo); + Rect behaviourRect = new Rect(initialX, Y + 10, maxBehaviourLabelSize.x, maxBehaviourLabelSize.y); + + GUI.Label(behaviourRect, new GUIContent("Network Behaviours"), styles.labelStyle); + // indent names + behaviourRect.x += 20; + behaviourRect.y += behaviourRect.height; + + foreach (NetworkBehaviourInfo info in behavioursInfo) + { + if (info.behaviour == null) + { + // could be the case in the editor after existing play mode. + continue; + } + + GUI.Label(behaviourRect, info.name, info.behaviour.enabled ? styles.componentName : styles.disabledName); + behaviourRect.y += behaviourRect.height; + Y = behaviourRect.y; + } + + return Y; + } + + float DrawObservers(NetworkIdentity identity, float initialX, float Y) + { + if (identity.observers.Count > 0) + { + Rect observerRect = new Rect(initialX, Y + 10, 200, 20); + + GUI.Label(observerRect, new GUIContent("Network observers"), styles.labelStyle); + // indent names + observerRect.x += 20; + observerRect.y += observerRect.height; + + foreach (KeyValuePair kvp in identity.observers) + { + GUI.Label(observerRect, $"{kvp.Value.address}:{kvp.Value}", styles.componentName); + observerRect.y += observerRect.height; + Y = observerRect.y; + } + } + + return Y; + } + + float DrawOwner(NetworkIdentity identity, float initialX, float Y) + { + if (identity.connectionToClient != null) + { + Rect ownerRect = new Rect(initialX, Y + 10, 400, 20); + GUI.Label(ownerRect, new GUIContent($"Client Authority: {identity.connectionToClient}"), styles.labelStyle); + Y += ownerRect.height; + } + return Y; + } + + // Get the maximum size used by the value of information items + Vector2 GetMaxNameLabelSize(IEnumerable infos) + { + Vector2 maxLabelSize = Vector2.zero; + foreach (NetworkIdentityInfo info in infos) + { + Vector2 labelSize = styles.labelStyle.CalcSize(info.value); + if (maxLabelSize.x < labelSize.x) + { + maxLabelSize.x = labelSize.x; + } + if (maxLabelSize.y < labelSize.y) + { + maxLabelSize.y = labelSize.y; + } + } + return maxLabelSize; + } + + Vector2 GetMaxBehaviourLabelSize(IEnumerable behavioursInfo) + { + Vector2 maxLabelSize = Vector2.zero; + foreach (NetworkBehaviourInfo behaviour in behavioursInfo) + { + Vector2 labelSize = styles.labelStyle.CalcSize(behaviour.name); + if (maxLabelSize.x < labelSize.x) + { + maxLabelSize.x = labelSize.x; + } + if (maxLabelSize.y < labelSize.y) + { + maxLabelSize.y = labelSize.y; + } + } + return maxLabelSize; + } + + IEnumerable GetNetworkIdentityInfo(NetworkIdentity identity) + { + List infos = new List + { + GetAssetId(identity), + GetString("Scene ID", identity.sceneId.ToString("X")) + }; + + if (Application.isPlaying) + { + infos.Add(GetString("Network ID", identity.netId.ToString())); + infos.Add(GetBoolean("Is Client", identity.isClient)); + infos.Add(GetBoolean("Is Server", identity.isServer)); + infos.Add(GetBoolean("Is Owned", identity.isOwned)); + infos.Add(GetBoolean("Is Local Player", identity.isLocalPlayer)); + } + return infos; + } + + IEnumerable GetNetworkBehaviorInfo(NetworkIdentity identity) + { + List behaviourInfos = new List(); + + NetworkBehaviour[] behaviours = identity.GetComponents(); + foreach (NetworkBehaviour behaviour in behaviours) + { + behaviourInfos.Add(new NetworkBehaviourInfo + { + name = new GUIContent(behaviour.GetType().FullName), + behaviour = behaviour + }); + } + return behaviourInfos; + } + + NetworkIdentityInfo GetAssetId(NetworkIdentity identity) + { + string assetId = identity.assetId.ToString(); + if (string.IsNullOrWhiteSpace(assetId)) + { + assetId = ""; + } + return GetString("Asset ID", assetId); + } + + static NetworkIdentityInfo GetString(string name, string value) + { + return new NetworkIdentityInfo + { + name = new GUIContent(name), + value = new GUIContent(value) + }; + } + + static NetworkIdentityInfo GetBoolean(string name, bool value) + { + return new NetworkIdentityInfo + { + name = new GUIContent(name), + value = new GUIContent((value ? "Yes" : "No")) + }; + } + } +} diff --git a/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta b/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta new file mode 100644 index 0000000..e67d4ea --- /dev/null +++ b/Assets/Mirror/Editor/NetworkInformationPreview.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 51a99294efe134232932c34606737356 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/NetworkInformationPreview.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs b/Assets/Mirror/Editor/NetworkManagerEditor.cs new file mode 100644 index 0000000..a7aa9bc --- /dev/null +++ b/Assets/Mirror/Editor/NetworkManagerEditor.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace Mirror +{ + [CustomEditor(typeof(NetworkManager), true)] + [CanEditMultipleObjects] + public class NetworkManagerEditor : Editor + { + SerializedProperty spawnListProperty; + ReorderableList spawnList; + protected NetworkManager networkManager; + + protected void Init() + { + if (spawnList == null) + { + networkManager = target as NetworkManager; + spawnListProperty = serializedObject.FindProperty("spawnPrefabs"); + spawnList = new ReorderableList(serializedObject, spawnListProperty) + { + drawHeaderCallback = DrawHeader, + drawElementCallback = DrawChild, + onReorderCallback = Changed, + onRemoveCallback = RemoveButton, + onChangedCallback = Changed, + onAddCallback = AddButton, + // this uses a 16x16 icon. other sizes make it stretch. + elementHeight = 16 + }; + } + } + + public override void OnInspectorGUI() + { + Init(); + DrawDefaultInspector(); + EditorGUI.BeginChangeCheck(); + spawnList.DoLayoutList(); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + } + + if (GUILayout.Button("Populate Spawnable Prefabs")) + { + ScanForNetworkIdentities(); + } + + // clicking the Populate button in a large project can add hundreds of entries. + // have a clear button in case that wasn't intended. + GUI.enabled = networkManager.spawnPrefabs.Count > 0; + if (GUILayout.Button("Clear Spawnable Prefabs")) + { + ClearNetworkIdentities(); + } + GUI.enabled = true; + } + + void ScanForNetworkIdentities() + { + List identities = new List(); + bool cancelled = false; + try + { + string[] paths = EditorHelper.IterateOverProject("t:prefab").ToArray(); + int count = 0; + foreach (string path in paths) + { + // ignore test & example prefabs. + // users sometimes keep the folders in their projects. + if (path.Contains("Mirror/Tests/") || + path.Contains("Mirror/Examples/")) + { + continue; + } + + if (EditorUtility.DisplayCancelableProgressBar("Searching for NetworkIdentities..", + $"Scanned {count}/{paths.Length} prefabs. Found {identities.Count} new ones", + count / (float)paths.Length)) + { + cancelled = true; + break; + } + + count++; + + NetworkIdentity ni = AssetDatabase.LoadAssetAtPath(path); + if (!ni) + { + continue; + } + + if (!networkManager.spawnPrefabs.Contains(ni.gameObject)) + { + identities.Add(ni.gameObject); + } + + } + } + finally + { + + EditorUtility.ClearProgressBar(); + if (!cancelled) + { + // RecordObject is needed for "*" to show up in Scene. + // however, this only saves List.Count without the entries. + Undo.RecordObject(networkManager, "NetworkManager: populated prefabs"); + + // add the entries + networkManager.spawnPrefabs.AddRange(identities); + + // sort alphabetically for better UX + networkManager.spawnPrefabs = networkManager.spawnPrefabs.OrderBy(go => go.name).ToList(); + + // SetDirty is required to save the individual entries properly. + EditorUtility.SetDirty(target); + } + // Loading assets might use a lot of memory, so try to unload them after + Resources.UnloadUnusedAssets(); + } + } + + void ClearNetworkIdentities() + { + // RecordObject is needed for "*" to show up in Scene. + // however, this only saves List.Count without the entries. + Undo.RecordObject(networkManager, "NetworkManager: cleared prefabs"); + + // add the entries + networkManager.spawnPrefabs.Clear(); + + // SetDirty is required to save the individual entries properly. + EditorUtility.SetDirty(target); + } + + static void DrawHeader(Rect headerRect) + { + GUI.Label(headerRect, "Registered Spawnable Prefabs:"); + } + + internal void DrawChild(Rect r, int index, bool isActive, bool isFocused) + { + SerializedProperty prefab = spawnListProperty.GetArrayElementAtIndex(index); + GameObject go = (GameObject)prefab.objectReferenceValue; + + GUIContent label; + if (go == null) + { + label = new GUIContent("Empty", "Drag a prefab with a NetworkIdentity here"); + } + else + { + NetworkIdentity identity = go.GetComponent(); + label = new GUIContent(go.name, identity != null ? $"AssetId: [{identity.assetId}]" : "No Network Identity"); + } + + GameObject newGameObject = (GameObject)EditorGUI.ObjectField(r, label, go, typeof(GameObject), false); + + if (newGameObject != go) + { + if (newGameObject != null && !newGameObject.GetComponent()) + { + Debug.LogError($"Prefab {newGameObject} cannot be added as spawnable as it doesn't have a NetworkIdentity."); + return; + } + prefab.objectReferenceValue = newGameObject; + } + } + + internal void Changed(ReorderableList list) + { + EditorUtility.SetDirty(target); + } + + internal void AddButton(ReorderableList list) + { + spawnListProperty.arraySize += 1; + list.index = spawnListProperty.arraySize - 1; + + SerializedProperty obj = spawnListProperty.GetArrayElementAtIndex(spawnListProperty.arraySize - 1); + obj.objectReferenceValue = null; + + spawnList.index = spawnList.count - 1; + + Changed(list); + } + + internal void RemoveButton(ReorderableList list) + { + spawnListProperty.DeleteArrayElementAtIndex(spawnList.index); + if (list.index >= spawnListProperty.arraySize) + { + list.index = spawnListProperty.arraySize - 1; + } + } + } +} diff --git a/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta b/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta new file mode 100644 index 0000000..78cc6d8 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkManagerEditor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 519712eb07f7a44039df57664811c2c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/NetworkManagerEditor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs b/Assets/Mirror/Editor/NetworkScenePostProcess.cs new file mode 100644 index 0000000..9baad1b --- /dev/null +++ b/Assets/Mirror/Editor/NetworkScenePostProcess.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; + +namespace Mirror +{ + public class NetworkScenePostProcess : MonoBehaviour + { + [PostProcessScene] + public static void OnPostProcessScene() + { + // find all NetworkIdentities in all scenes + // => can't limit it to GetActiveScene() because that wouldn't work + // for additive scene loads (the additively loaded scene is never + // the active scene) + // => ignore DontDestroyOnLoad scene! this avoids weird situations + // like in NetworkZones when we destroy the local player and + // load another scene afterwards, yet the local player is still + // in the FindObjectsOfType result with scene=DontDestroyOnLoad + // for some reason + // => OfTypeAll so disabled objects are included too + // => Unity 2019 returns prefabs here too, so filter them out. + IEnumerable identities = Resources.FindObjectsOfTypeAll() + .Where(identity => identity.gameObject.hideFlags != HideFlags.NotEditable && + identity.gameObject.hideFlags != HideFlags.HideAndDontSave && + identity.gameObject.scene.name != "DontDestroyOnLoad" && + !Utils.IsPrefab(identity.gameObject)); + + foreach (NetworkIdentity identity in identities) + { + // if we had a [ConflictComponent] attribute that would be better than this check. + // also there is no context about which scene this is in. + if (identity.GetComponent() != null) + Debug.LogError("NetworkManager has a NetworkIdentity component. This will cause the NetworkManager object to be disabled, so it is not recommended."); + + // not spawned before? + // OnPostProcessScene is called after additive scene loads too, + // and we don't want to set main scene's objects inactive again + if (!identity.isClient && !identity.isServer) + { + // valid scene object? + // otherwise it might be an unopened scene that still has null + // sceneIds. builds are interrupted if they contain 0 sceneIds, + // but it's still possible that we call LoadScene in Editor + // for a previously unopened scene. + // (and only do SetActive if this was actually a scene object) + if (identity.sceneId != 0) + { + PrepareSceneObject(identity); + } + // throwing an exception would only show it for one object + // because this function would return afterwards. + else + { + // there are two cases where sceneId == 0: + // if we have a prefab open in the prefab scene + string path = identity.gameObject.scene.path; + if (string.IsNullOrWhiteSpace(path)) + { + // pressing play while in prefab edit mode used to freeze/crash Unity 2019. + // this seems fine now so we don't need to stop the editor anymore. +#if UNITY_2020_3_OR_NEWER + Debug.LogWarning($"{identity.name} was open in Prefab Edit Mode while launching with Mirror. If this causes issues, please let us know."); +#else + Debug.LogError($"{identity.name} is currently open in Prefab Edit Mode. Please open the actual scene before launching Mirror."); + EditorApplication.isPlaying = false; +#endif + } + // if an unopened scene needs resaving + else + { + + // nothing good will happen when trying to launch with invalid sceneIds. + // show an error and stop playing immediately. + Debug.LogError($"Scene {path} needs to be opened and resaved, because the scene object {identity.name} has no valid sceneId yet."); + EditorApplication.isPlaying = false; + } + } + } + } + } + + static void PrepareSceneObject(NetworkIdentity identity) + { + // set scene hash + identity.SetSceneIdSceneHashPartInternal(); + + // spawnable scene objects are force disabled on scene load to + // ensure Start/Update/etc. aren't called until actually spawned. + // + // note: NetworkIdentity.OnDisable adds itself to the + // spawnableObjects dictionary (only if sceneId != 0) + identity.gameObject.SetActive(false); + + // safety check for prefabs with more than one NetworkIdentity + GameObject prefabGO = PrefabUtility.GetCorrespondingObjectFromSource(identity.gameObject); + if (prefabGO) + { + GameObject prefabRootGO = prefabGO.transform.root.gameObject; + if (prefabRootGO != null && prefabRootGO.GetComponentsInChildren().Length > 1) + Debug.LogWarning($"Prefab {prefabRootGO.name} has several NetworkIdentity components attached to itself or its children, this is not supported."); + } + } + } +} diff --git a/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta b/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta new file mode 100644 index 0000000..2ea2e63 --- /dev/null +++ b/Assets/Mirror/Editor/NetworkScenePostProcess.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a3ec1c414d821444a9e77f18a2c130ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/NetworkScenePostProcess.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/ReadOnlyDrawer.cs b/Assets/Mirror/Editor/ReadOnlyDrawer.cs new file mode 100644 index 0000000..4a09707 --- /dev/null +++ b/Assets/Mirror/Editor/ReadOnlyDrawer.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using UnityEditor; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] + public class ReadOnlyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // Cache the current GUI enabled state + bool prevGuiEnabledState = GUI.enabled; + + GUI.enabled = false; + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = prevGuiEnabledState; + } + } +} diff --git a/Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta b/Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta new file mode 100644 index 0000000..81d626f --- /dev/null +++ b/Assets/Mirror/Editor/ReadOnlyDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 22f17bdd21f104c41bc175937fefbdec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/ReadOnlyDrawer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/SceneDrawer.cs b/Assets/Mirror/Editor/SceneDrawer.cs new file mode 100644 index 0000000..f391684 --- /dev/null +++ b/Assets/Mirror/Editor/SceneDrawer.cs @@ -0,0 +1,47 @@ +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(SceneAttribute))] + public class SceneDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType == SerializedPropertyType.String) + { + SceneAsset sceneObject = AssetDatabase.LoadAssetAtPath(property.stringValue); + + if (sceneObject == null && !string.IsNullOrWhiteSpace(property.stringValue)) + { + // try to load it from the build settings for legacy compatibility + sceneObject = GetBuildSettingsSceneObject(property.stringValue); + } + if (sceneObject == null && !string.IsNullOrWhiteSpace(property.stringValue)) + { + Debug.LogError($"Could not find scene {property.stringValue} in {property.propertyPath}, assign the proper scenes in your NetworkManager"); + } + SceneAsset scene = (SceneAsset)EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true); + + property.stringValue = AssetDatabase.GetAssetPath(scene); + } + else + { + EditorGUI.LabelField(position, label.text, "Use [Scene] with strings."); + } + } + + protected SceneAsset GetBuildSettingsSceneObject(string sceneName) + { + foreach (EditorBuildSettingsScene buildScene in EditorBuildSettings.scenes) + { + SceneAsset sceneAsset = AssetDatabase.LoadAssetAtPath(buildScene.path); + if (sceneAsset!= null && sceneAsset.name == sceneName) + { + return sceneAsset; + } + } + return null; + } + } +} diff --git a/Assets/Mirror/Editor/SceneDrawer.cs.meta b/Assets/Mirror/Editor/SceneDrawer.cs.meta new file mode 100644 index 0000000..04d6cdc --- /dev/null +++ b/Assets/Mirror/Editor/SceneDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b24704a46211b4ea294aba8f58715cea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/SceneDrawer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs new file mode 100644 index 0000000..735b018 --- /dev/null +++ b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs @@ -0,0 +1,89 @@ +// helper class for NetworkBehaviourInspector to draw all enumerable SyncObjects +// (SyncList/Set/Dictionary) +// 'SyncObjectCollectionsDrawer' is a nicer name than 'IEnumerableSyncObjectsDrawer' +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; + +namespace Mirror +{ + class SyncObjectCollectionField + { + public bool visible; + public readonly FieldInfo field; + public readonly string label; + + public SyncObjectCollectionField(FieldInfo field) + { + this.field = field; + visible = false; + + // field.FieldType.Name has a backtick and number at the end, e.g. SyncList`1 + // so we split it and only take the first part so it looks nicer. + // e.g. SyncList`1 -> SyncList + // Better to do it one time here than in hot path in OnInspectorGUI + label = $"{field.Name} [{Regex.Replace(field.FieldType.Name, @"`\d+", "")}]"; + } + } + + public class SyncObjectCollectionsDrawer + { + readonly UnityEngine.Object targetObject; + readonly List syncObjectCollectionFields; + + public SyncObjectCollectionsDrawer(UnityEngine.Object targetObject) + { + this.targetObject = targetObject; + syncObjectCollectionFields = new List(); + foreach (FieldInfo field in InspectorHelper.GetAllFields(targetObject.GetType(), typeof(NetworkBehaviour))) + { + // only draw SyncObjects that are IEnumerable (SyncList/Set/Dictionary) + if (field.IsVisibleSyncObject() && + field.ImplementsInterface() && + field.ImplementsInterface()) + { + syncObjectCollectionFields.Add(new SyncObjectCollectionField(field)); + } + } + } + + public void Draw() + { + if (syncObjectCollectionFields.Count == 0) { return; } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Sync Collections", EditorStyles.boldLabel); + + for (int i = 0; i < syncObjectCollectionFields.Count; i++) + { + DrawSyncObjectCollection(syncObjectCollectionFields[i]); + } + } + + void DrawSyncObjectCollection(SyncObjectCollectionField syncObjectCollectionField) + { + syncObjectCollectionField.visible = EditorGUILayout.Foldout(syncObjectCollectionField.visible, syncObjectCollectionField.label); + if (syncObjectCollectionField.visible) + { + using (new EditorGUI.IndentLevelScope()) + { + object fieldValue = syncObjectCollectionField.field.GetValue(targetObject); + if (fieldValue is IEnumerable syncObject) + { + int index = 0; + foreach (object item in syncObject) + { + string itemValue = item != null ? item.ToString() : "NULL"; + string itemLabel = $"Element {index}"; + EditorGUILayout.LabelField(itemLabel, itemValue); + + index++; + } + } + } + } + } + } +} diff --git a/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs.meta b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs.meta new file mode 100644 index 0000000..b830f9a --- /dev/null +++ b/Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6f90afab12e04f0e945d83e9d38308a3 +timeCreated: 1632556645 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/SyncObjectCollectionsDrawer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs new file mode 100644 index 0000000..2356a5e --- /dev/null +++ b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs @@ -0,0 +1,28 @@ +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + [CustomPropertyDrawer(typeof(SyncVarAttribute))] + public class SyncVarAttributeDrawer : PropertyDrawer + { + static readonly GUIContent syncVarIndicatorContent = new GUIContent("SyncVar", "This variable has been marked with the [SyncVar] attribute."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Vector2 syncVarIndicatorRect = EditorStyles.miniLabel.CalcSize(syncVarIndicatorContent); + float valueWidth = position.width - syncVarIndicatorRect.x; + + Rect valueRect = new Rect(position.x, position.y, valueWidth, position.height); + Rect labelRect = new Rect(position.x + valueWidth, position.y, syncVarIndicatorRect.x, position.height); + + EditorGUI.PropertyField(valueRect, property, label, true); + GUI.Label(labelRect, syncVarIndicatorContent, EditorStyles.miniLabel); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property); + } + } +} diff --git a/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta new file mode 100644 index 0000000..3a9216d --- /dev/null +++ b/Assets/Mirror/Editor/SyncVarAttributeDrawer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 27821afc81c4d064d8348fbeb00c0ce8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/SyncVarAttributeDrawer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver.meta b/Assets/Mirror/Editor/Weaver.meta new file mode 100644 index 0000000..121fbf4 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9f8e6274119b4ce29e498cfb8aca8a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs new file mode 100644 index 0000000..08b43f5 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Mirror.Tests")] diff --git a/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta new file mode 100644 index 0000000..a58871b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/AssemblyInfo.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 929924d95663264478d4238d4910d22e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/AssemblyInfo.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint.meta b/Assets/Mirror/Editor/Weaver/EntryPoint.meta new file mode 100644 index 0000000..54b718a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 251338e67afb4cefa38da924f8c50a6e +timeCreated: 1628851818 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs new file mode 100644 index 0000000..b5db851 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs @@ -0,0 +1,188 @@ +// for Unity 2020+ we use ILPostProcessor. +// only automatically invoke it for older versions. +#if !UNITY_2020_3_OR_NEWER +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.CecilX; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEngine; +using UnityAssembly = UnityEditor.Compilation.Assembly; + +namespace Mirror.Weaver +{ + public static class CompilationFinishedHook + { + // needs to be the same as Weaver.MirrorAssemblyName! + const string MirrorRuntimeAssemblyName = "Mirror"; + const string MirrorWeaverAssemblyName = "Mirror.Weaver"; + + // global weaver define so that tests can use it + internal static Weaver weaver; + + // delegate for subscription to Weaver warning messages + public static Action OnWeaverWarning; + // delete for subscription to Weaver error messages + public static Action OnWeaverError; + + // controls whether Weaver errors are reported direct to the Unity console (tests enable this) + public static bool UnityLogEnabled = true; + + [InitializeOnLoadMethod] + public static void OnInitializeOnLoad() + { + CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished; + + // We only need to run this once per session + // after that, all assemblies will be weaved by the event + if (!SessionState.GetBool("MIRROR_WEAVED", false)) + { + // reset session flag + SessionState.SetBool("MIRROR_WEAVED", true); + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); + + WeaveExistingAssemblies(); + } + } + + public static void WeaveExistingAssemblies() + { + foreach (UnityAssembly assembly in CompilationPipeline.GetAssemblies()) + { + if (File.Exists(assembly.outputPath)) + { + OnCompilationFinished(assembly.outputPath, new CompilerMessage[0]); + } + } + + EditorUtility.RequestScriptReload(); + } + + static Assembly FindCompilationPipelineAssembly(string assemblyName) => + CompilationPipeline.GetAssemblies().First(assembly => assembly.name == assemblyName); + + static bool CompilerMessagesContainError(CompilerMessage[] messages) => + messages.Any(msg => msg.type == CompilerMessageType.Error); + + public static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) + { + // Do nothing if there were compile errors on the target + if (CompilerMessagesContainError(messages)) + { + Debug.Log("Weaver: stop because compile errors on target"); + return; + } + + // Should not run on the editor only assemblies (test ones still need to be weaved) + if (assemblyPath.Contains("-Editor") || + (assemblyPath.Contains(".Editor") && !assemblyPath.Contains(".Tests"))) + { + return; + } + + // skip Mirror.dll because CompilationFinishedHook can't weave itself. + // this would cause a sharing violation. + // skip Mirror.Weaver.dll too. + string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); + if (assemblyName == MirrorRuntimeAssemblyName || assemblyName == MirrorWeaverAssemblyName) + { + return; + } + + // find Mirror.dll + Assembly mirrorAssembly = FindCompilationPipelineAssembly(MirrorRuntimeAssemblyName); + if (mirrorAssembly == null) + { + Debug.LogError("Failed to find Mirror runtime assembly"); + return; + } + + string mirrorRuntimeDll = mirrorAssembly.outputPath; + if (!File.Exists(mirrorRuntimeDll)) + { + // this is normal, it happens with any assembly that is built before mirror + // such as unity packages or your own assemblies + // those don't need to be weaved + // if any assembly depends on mirror, then it will be built after + return; + } + + // find UnityEngine.CoreModule.dll + string unityEngineCoreModuleDLL = UnityEditorInternal.InternalEditorUtility.GetEngineCoreModuleAssemblyPath(); + if (string.IsNullOrEmpty(unityEngineCoreModuleDLL)) + { + Debug.LogError("Failed to find UnityEngine assembly"); + return; + } + + HashSet dependencyPaths = GetDependencyPaths(assemblyPath); + dependencyPaths.Add(Path.GetDirectoryName(mirrorRuntimeDll)); + dependencyPaths.Add(Path.GetDirectoryName(unityEngineCoreModuleDLL)); + + if (!WeaveFromFile(assemblyPath, dependencyPaths.ToArray())) + { + // Set false...will be checked in \Editor\EnterPlayModeSettingsCheck.CheckSuccessfulWeave() + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", false); + if (UnityLogEnabled) Debug.LogError($"Weaving failed for {assemblyPath}"); + } + } + + static HashSet GetDependencyPaths(string assemblyPath) + { + // build directory list for later asm/symbol resolving using CompilationPipeline refs + HashSet dependencyPaths = new HashSet + { + Path.GetDirectoryName(assemblyPath) + }; + foreach (Assembly assembly in CompilationPipeline.GetAssemblies()) + { + if (assembly.outputPath == assemblyPath) + { + foreach (string reference in assembly.compiledAssemblyReferences) + { + dependencyPaths.Add(Path.GetDirectoryName(reference)); + } + } + } + + return dependencyPaths; + } + // helper function to invoke Weaver with an AssemblyDefinition from a + // file path, with dependencies added. + static bool WeaveFromFile(string assemblyPath, string[] dependencies) + { + // resolve assembly from stream + using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver()) + using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters{ ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver })) + { + // add this assembly's path and unity's assembly path + asmResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); + asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName()); + + // add dependencies + if (dependencies != null) + { + foreach (string path in dependencies) + { + asmResolver.AddSearchDirectory(path); + } + } + + // create weaver with logger + weaver = new Weaver(new CompilationFinishedLogger()); + if (weaver.Weave(assembly, asmResolver, out bool modified)) + { + // write changes to file if modified + if (modified) + assembly.Write(new WriterParameters{WriteSymbols = true}); + + return true; + } + return false; + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta new file mode 100644 index 0000000..33e73f7 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: de2aeb2e8068f421a9a1febe408f7051 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedHook.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs new file mode 100644 index 0000000..e053404 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs @@ -0,0 +1,31 @@ +// logger for compilation finished hook. +// where we need a callback and Debug.Log. +// for Unity 2020+ we use ILPostProcessor. +#if !UNITY_2020_3_OR_NEWER +using Mono.CecilX; +using UnityEngine; + +namespace Mirror.Weaver +{ + public class CompilationFinishedLogger : Logger + { + public void Warning(string message) => Warning(message, null); + public void Warning(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + + if (CompilationFinishedHook.UnityLogEnabled) Debug.LogWarning(message); + CompilationFinishedHook.OnWeaverWarning?.Invoke(message); + } + + public void Error(string message) => Error(message, null); + public void Error(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + + if (CompilationFinishedHook.UnityLogEnabled) Debug.LogError(message); + CompilationFinishedHook.OnWeaverError?.Invoke(message); + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta new file mode 100644 index 0000000..3d07ffc --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 47026732f0fa475c94bd1dd41f1de559 +timeCreated: 1629379868 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPoint/CompilationFinishedLogger.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs new file mode 100644 index 0000000..5dffa97 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs @@ -0,0 +1,44 @@ +#if !UNITY_2020_3_OR_NEWER +// make sure we weaved successfully when entering play mode. +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + public class EnterPlayModeSettingsCheck : MonoBehaviour + { + [InitializeOnLoadMethod] + static void OnInitializeOnLoad() + { + // Hook this event to see if we have a good weave every time + // user attempts to enter play mode or tries to do a build + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + static void OnPlayModeStateChanged(PlayModeStateChange state) + { + // Per Unity docs, this fires "when exiting edit mode before the Editor is in play mode". + // This doesn't fire when closing the editor. + if (state == PlayModeStateChange.ExitingEditMode) + { + // Check if last weave result was successful + if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) + { + // Last weave result was a failure...try to weave again + // Faults will show in the console that may have been cleared by "Clear on Play" + SessionState.SetBool("MIRROR_WEAVE_SUCCESS", true); + Weaver.CompilationFinishedHook.WeaveExistingAssemblies(); + + // Did that clear things up for us? + if (!SessionState.GetBool("MIRROR_WEAVE_SUCCESS", false)) + { + // Nope, still failed, and console has the issues logged + Debug.LogError("Can't enter play mode until weaver issues are resolved."); + EditorApplication.isPlaying = false; + } + } + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta new file mode 100644 index 0000000..af6dddc --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b73d0f106ba84aa983baa5142b08a0a9 +timeCreated: 1628851346 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPoint/EnterPlayModeHook.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta new file mode 100644 index 0000000..d1fa101 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09082db63d1d48d9ab91320165c1b684 +timeCreated: 1628859005 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs new file mode 100644 index 0000000..e4d9de2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs @@ -0,0 +1,31 @@ +// tests use WeaveAssembler, which uses AssemblyBuilder to Build(). +// afterwards ILPostProcessor weaves the build. +// this works on windows, but build() does not run ILPP on mac atm. +// we need to manually invoke ILPP with an assembly from file. +// +// this is in Weaver folder becuase CompilationPipeline can only be accessed +// from assemblies with the name "Unity.*.CodeGen" +using System.IO; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + public class CompiledAssemblyFromFile : ICompiledAssembly + { + readonly string assemblyPath; + + public string Name => Path.GetFileNameWithoutExtension(assemblyPath); + public string[] References { get; set; } + public string[] Defines { get; set; } + public InMemoryAssembly InMemoryAssembly { get; } + + public CompiledAssemblyFromFile(string assemblyPath) + { + this.assemblyPath = assemblyPath; + byte[] peData = File.ReadAllBytes(assemblyPath); + string pdbFileName = Path.GetFileNameWithoutExtension(assemblyPath) + ".pdb"; + byte[] pdbData = File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(assemblyPath), pdbFileName)); + InMemoryAssembly = new InMemoryAssembly(peData, pdbData); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta new file mode 100644 index 0000000..c442f3b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9009d1db4ed44f6694a92bf8ad7738e9 +timeCreated: 1630129423 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/CompiledAssemblyFromFile.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs new file mode 100644 index 0000000..0823234 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs @@ -0,0 +1,205 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// an assembly resolver's job is to open an assembly in case we want to resolve +// a type from it. +// +// for example, while weaving MyGame.dll: if we want to resolve ArraySegment, +// then we need to open and resolve from another assembly (CoreLib). +// +// using DefaultAssemblyResolver with ILPostProcessor throws Exceptions in +// WeaverTypes.cs when resolving anything, for example: +// ArraySegment in Mirror.Tests.Dll. +// +// we need a custom resolver for ILPostProcessor. +#if UNITY_2020_3_OR_NEWER +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Linq; +using System.Threading; +using Mono.CecilX; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + class ILPostProcessorAssemblyResolver : IAssemblyResolver + { + readonly string[] assemblyReferences; + + // originally we used Dictionary + lock. + // Resolve() is called thousands of times for large projects. + // ILPostProcessor is multithreaded, so best to use ConcurrentDictionary without the lock here. + readonly ConcurrentDictionary assemblyCache = + new ConcurrentDictionary(); + + // Resolve() calls FindFile() every time. + // thousands of times for String => mscorlib alone in large projects. + // cache the results! ILPostProcessor is multithreaded, so use a ConcurrentDictionary here. + readonly ConcurrentDictionary fileNameCache = + new ConcurrentDictionary(); + + readonly ICompiledAssembly compiledAssembly; + AssemblyDefinition selfAssembly; + + readonly Logger Log; + + public ILPostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly, Logger Log) + { + this.compiledAssembly = compiledAssembly; + assemblyReferences = compiledAssembly.References; + this.Log = Log; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + // Cleanup + } + + public AssemblyDefinition Resolve(AssemblyNameReference name) => + Resolve(name, new ReaderParameters(ReadingMode.Deferred)); + + // here is an example on when this is called: + // Player : NetworkBehaviour has a [SyncVar] of type String. + // Weaver's SyncObjectInitializer checks if ImplementsSyncObject() + // which needs to resolve the type 'String' from mscorlib. + // Resolve() lives in CecilX.MetadataResolver.Resolve() + // which calls assembly_resolver.Resolve(). + // which uses our ILPostProcessorAssemblyResolver here. + // + // for large projects, this is called thousands of times for mscorlib alone. + // initially ILPostProcessorAssemblyResolver took 30x longer than with CompilationFinishedHook. + // we need to cache and speed up everything we can here! + public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + { + if (name.Name == compiledAssembly.Name) + return selfAssembly; + + // cache FindFile. + // in large projects, this is called thousands(!) of times for String=>mscorlib alone. + // reduces a single String=>mscorlib resolve from 0.771ms to 0.015ms. + // => 50x improvement in TypeReference.Resolve() speed! + // => 22x improvement in Weaver speed! + if (!fileNameCache.TryGetValue(name.Name, out string fileName)) + { + fileName = FindFile(name.Name); + fileNameCache.TryAdd(name.Name, fileName); + } + + if (fileName == null) + { + // returning null will throw exceptions in our weaver where. + // let's make it obvious why we returned null for easier debugging. + // NOTE: if this fails for "System.Private.CoreLib": + // ILPostProcessorReflectionImporter fixes it! + + // the fix for #2503 started showing this warning for Bee.BeeDriver on mac, + // which is for compilation. we can ignore that one. + if (!name.Name.StartsWith("Bee.BeeDriver")) + { + Log.Warning($"ILPostProcessorAssemblyResolver.Resolve: Failed to find file for {name}"); + } + return null; + } + + // try to get cached assembly by filename + writetime + DateTime lastWriteTime = File.GetLastWriteTime(fileName); + string cacheKey = fileName + lastWriteTime; + if (assemblyCache.TryGetValue(cacheKey, out AssemblyDefinition result)) + return result; + + // otherwise resolve and cache a new assembly + parameters.AssemblyResolver = this; + MemoryStream ms = MemoryStreamFor(fileName); + + string pdb = fileName + ".pdb"; + if (File.Exists(pdb)) + parameters.SymbolStream = MemoryStreamFor(pdb); + + AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters); + assemblyCache.TryAdd(cacheKey, assemblyDefinition); + return assemblyDefinition; + } + + // find assemblyname in assembly's references + string FindFile(string name) + { + // perhaps the type comes from a .dll or .exe + // check both in one call without Linq instead of iterating twice like originally + foreach (string r in assemblyReferences) + { + if (Path.GetFileNameWithoutExtension(r) == name) + return r; + } + + // this is called thousands(!) of times. + // constructing strings only once saves ~0.1ms per call for mscorlib. + string dllName = name + ".dll"; + + // Unfortunately the current ICompiledAssembly API only provides direct references. + // It is very much possible that a postprocessor ends up investigating a type in a directly + // referenced assembly, that contains a field that is not in a directly referenced assembly. + // if we don't do anything special for that situation, it will fail to resolve. We should fix this + // in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references + // are always located next to direct references, so we search in all directories of direct references we + // got passed, and if we find the file in there, we resolve to it. + foreach (string parentDir in assemblyReferences.Select(Path.GetDirectoryName).Distinct()) + { + string candidate = Path.Combine(parentDir, dllName); + if (File.Exists(candidate)) + return candidate; + } + + return null; + } + + // open file as MemoryStream. + // ILPostProcessor is multithreaded. + // retry a few times in case another thread is still accessing the file. + static MemoryStream MemoryStreamFor(string fileName) + { + return Retry(10, TimeSpan.FromSeconds(1), () => + { + byte[] byteArray; + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + byteArray = new byte[fs.Length]; + int readLength = fs.Read(byteArray, 0, (int)fs.Length); + if (readLength != fs.Length) + throw new InvalidOperationException("File read length is not full length of file."); + } + + return new MemoryStream(byteArray); + }); + } + + static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func func) + { + try + { + return func(); + } + catch (IOException) + { + if (retryCount == 0) + throw; + Console.WriteLine($"Caught IO Exception, trying {retryCount} more times"); + Thread.Sleep(waitTime); + return Retry(retryCount - 1, waitTime, func); + } + } + + // if the CompiledAssembly's AssemblyDefinition is known, we can add it + public void SetAssemblyDefinitionForCompiledAssembly(AssemblyDefinition assemblyDefinition) + { + selfAssembly = assemblyDefinition; + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta new file mode 100644 index 0000000..1ece15f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0b3e94696e22440ead0b3a42411bbe14 +timeCreated: 1629693784 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorAssemblyResolver.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs new file mode 100644 index 0000000..6a70641 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs @@ -0,0 +1,53 @@ +// helper function to use ILPostProcessor for an assembly from file. +// we keep this in Weaver folder because we can access CompilationPipleine here. +// in tests folder we can't, unless we rename to "Unity.*.CodeGen", +// but then tests wouldn't be weaved anymore. +#if UNITY_2020_3_OR_NEWER +using System; +using System.IO; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Mirror.Weaver +{ + public static class ILPostProcessorFromFile + { + // read, weave, write file via ILPostProcessor + public static void ILPostProcessFile(string assemblyPath, string[] references, Action OnWarning, Action OnError) + { + // we COULD Weave() with a test logger manually. + // but for test result consistency on all platforms, + // let's invoke the ILPostProcessor here too. + CompiledAssemblyFromFile assembly = new CompiledAssemblyFromFile(assemblyPath); + assembly.References = references; + + // create ILPP and check WillProcess like Unity would. + ILPostProcessorHook ilpp = new ILPostProcessorHook(); + if (ilpp.WillProcess(assembly)) + { + //Debug.Log($"Will Process: {assembly.Name}"); + + // process it like Unity would + ILPostProcessResult result = ilpp.Process(assembly); + + // handle the error messages like Unity would + foreach (DiagnosticMessage message in result.Diagnostics) + { + if (message.DiagnosticType == DiagnosticType.Warning) + { + OnWarning(message.MessageData); + } + else if (message.DiagnosticType == DiagnosticType.Error) + { + OnError(message.MessageData); + } + } + + // save the weaved assembly to file. + // some tests open it and check for certain IL code. + File.WriteAllBytes(assemblyPath, result.InMemoryAssembly.PeData); + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta new file mode 100644 index 0000000..b7dabcc --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2a4b115486b74d27a9540f3c39ae2d46 +timeCreated: 1630152191 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorFromFile.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs new file mode 100644 index 0000000..0cfb433 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs @@ -0,0 +1,143 @@ +// hook via ILPostProcessor from Unity 2020.3+ +// (2020.1 has errors https://github.com/vis2k/Mirror/issues/2912) +#if UNITY_2020_3_OR_NEWER +// Unity.CompilationPipeline reference is only resolved if assembly name is +// Unity.*.CodeGen: +// https://forum.unity.com/threads/how-does-unity-do-codegen-and-why-cant-i-do-it-myself.853867/#post-5646937 +using System.IO; +using System.Linq; +// to use Mono.CecilX here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX. +// otherwise we get a reflection exception with 'file not found: CecilX'. +using Mono.CecilX; +using Mono.CecilX.Cil; +using Unity.CompilationPipeline.Common.ILPostProcessing; +// IMPORTANT: 'using UnityEngine' does not work in here. +// Unity gives "(0,0): error System.Security.SecurityException: ECall methods must be packaged into a system module." +//using UnityEngine; + +namespace Mirror.Weaver +{ + public class ILPostProcessorHook : ILPostProcessor + { + // from CompilationFinishedHook + const string MirrorRuntimeAssemblyName = "Mirror"; + + // ILPostProcessor is invoked by Unity. + // we can not tell it to ignore certain assemblies before processing. + // add a 'ignore' define for convenience. + // => WeaverTests/WeaverAssembler need it to avoid Unity running it + public const string IgnoreDefine = "ILPP_IGNORE"; + + // we can't use Debug.Log in ILPP, so we need a custom logger + ILPostProcessorLogger Log = new ILPostProcessorLogger(); + + // ??? + public override ILPostProcessor GetInstance() => this; + + // check if assembly has the 'ignore' define + static bool HasDefine(ICompiledAssembly assembly, string define) => + assembly.Defines != null && + assembly.Defines.Contains(define); + + // process Mirror, or anything that references Mirror + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + // compiledAssembly.References are file paths: + // Library/Bee/artifacts/200b0aE.dag/Mirror.CompilerSymbols.dll + // Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll + // /Applications/Unity/Hub/Editor/2021.2.0b6_apple_silicon/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + // + // log them to see: + // foreach (string reference in compiledAssembly.References) + // LogDiagnostics($"{compiledAssembly.Name} references {reference}"); + bool relevant = compiledAssembly.Name == MirrorRuntimeAssemblyName || + compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == MirrorRuntimeAssemblyName); + bool ignore = HasDefine(compiledAssembly, IgnoreDefine); + return relevant && !ignore; + } + + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + //Log.Warning($"Processing {compiledAssembly.Name}"); + + // load the InMemoryAssembly peData into a MemoryStream + byte[] peData = compiledAssembly.InMemoryAssembly.PeData; + //LogDiagnostics($" peData.Length={peData.Length} bytes"); + using (MemoryStream stream = new MemoryStream(peData)) + using (ILPostProcessorAssemblyResolver asmResolver = new ILPostProcessorAssemblyResolver(compiledAssembly, Log)) + { + // we need to load symbols. otherwise we get: + // "(0,0): error Mono.CecilX.Cil.SymbolsNotFoundException: No symbol found for file: " + using (MemoryStream symbols = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData)) + { + ReaderParameters readerParameters = new ReaderParameters{ + SymbolStream = symbols, + ReadWrite = true, + ReadSymbols = true, + AssemblyResolver = asmResolver, + // custom reflection importer to fix System.Private.CoreLib + // not being found in custom assembly resolver above. + ReflectionImporterProvider = new ILPostProcessorReflectionImporterProvider() + }; + using (AssemblyDefinition asmDef = AssemblyDefinition.ReadAssembly(stream, readerParameters)) + { + // resolving a Mirror.dll type like NetworkServer while + // weaving Mirror.dll does not work. it throws a + // NullReferenceException in WeaverTypes.ctor + // when Resolve() is called on the first Mirror type. + // need to add the AssemblyDefinition itself to use. + asmResolver.SetAssemblyDefinitionForCompiledAssembly(asmDef); + + // weave this assembly. + Weaver weaver = new Weaver(Log); + if (weaver.Weave(asmDef, asmResolver, out bool modified)) + { + //Log.Warning($"Weaving succeeded for: {compiledAssembly.Name}"); + + // write if modified + if (modified) + { + // when weaving Mirror.dll with ILPostProcessor, + // Weave() -> WeaverTypes -> resolving the first + // type in Mirror.dll adds a reference to + // Mirror.dll even though we are in Mirror.dll. + // -> this would throw an exception: + // "Mirror references itself" and not compile + // -> need to detect and fix manually here + if (asmDef.MainModule.AssemblyReferences.Any(r => r.Name == asmDef.Name.Name)) + { + asmDef.MainModule.AssemblyReferences.Remove(asmDef.MainModule.AssemblyReferences.First(r => r.Name == asmDef.Name.Name)); + //Log.Warning($"fixed self referencing Assembly: {asmDef.Name.Name}"); + } + + MemoryStream peOut = new MemoryStream(); + MemoryStream pdbOut = new MemoryStream(); + WriterParameters writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), + SymbolStream = pdbOut, + WriteSymbols = true + }; + + asmDef.Write(peOut, writerParameters); + + InMemoryAssembly inMemory = new InMemoryAssembly(peOut.ToArray(), pdbOut.ToArray()); + return new ILPostProcessResult(inMemory, Log.Logs); + } + } + // if anything during Weave() fails, we log an error. + // don't need to indicate 'weaving failed' again. + // in fact, this would break tests only expecting certain errors. + //else Log.Error($"Weaving failed for: {compiledAssembly.Name}"); + } + } + } + + // always return an ILPostProcessResult with Logs. + // otherwise we won't see Logs if weaving failed. + return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, Log.Logs); + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta new file mode 100644 index 0000000..7b16277 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 5f113eb695b348b5b28cd85358c8959a +timeCreated: 1628859074 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorHook.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs new file mode 100644 index 0000000..e8595fd --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Mono.CecilX; +using Unity.CompilationPipeline.Common.Diagnostics; + +namespace Mirror.Weaver +{ + public class ILPostProcessorLogger : Logger + { + // can't Debug.Log in ILPostProcessor. need to add to this list. + internal List Logs = new List(); + + void Add(string message, DiagnosticType logType) + { + Logs.Add(new DiagnosticMessage + { + // TODO add file etc. for double click opening later? + DiagnosticType = logType, // doesn't have .Log + File = null, + Line = 0, + Column = 0, + MessageData = message + }); + } + + public void LogDiagnostics(string message, DiagnosticType logType = DiagnosticType.Warning) + { + // TODO IN-44868 FIX IS IN 2021.3.32f1, 2022.3.11f1, 2023.2.0b13 and 2023.3.0a8 + // DiagnosticMessage can't display \n for some reason. + // it just cuts it off and we don't see any stack trace. + // so let's replace all line breaks so we get the stack trace. + // (Unity 2021.2.0b6 apple silicon) + //message = message.Replace("\n", "/"); + + // lets break it into several messages instead so it's easier readable + string[] lines = message.Split('\n'); + + // if it's just one line, simply log it + if (lines.Length == 1) + { + // tests assume exact message log. + // don't include 'Weaver: ...' or similar. + Add($"{message}", logType); + } + // for multiple lines, log each line separately with start/end indicators + else + { + // first line with Weaver: ... first + Add("----------------------------------------------", logType); + foreach (string line in lines) Add(line, logType); + Add("----------------------------------------------", logType); + } + } + + public void Warning(string message) => Warning(message, null); + public void Warning(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + LogDiagnostics(message, DiagnosticType.Warning); + } + + public void Error(string message) => Error(message, null); + public void Error(string message, MemberReference mr) + { + if (mr != null) message = $"{message} (at {mr})"; + LogDiagnostics(message, DiagnosticType.Error); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta new file mode 100644 index 0000000..dee8c87 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e7b56e7826664e34a415e4b70d958f2a +timeCreated: 1629533154 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorLogger.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs new file mode 100644 index 0000000..e15c103 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs @@ -0,0 +1,36 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// ILPostProcessorAssemblyRESOLVER does not find the .dll file for: +// "System.Private.CoreLib" +// we need this custom reflection importer to fix that. +using System.Linq; +using System.Reflection; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + internal class ILPostProcessorReflectionImporter : DefaultReflectionImporter + { + const string SystemPrivateCoreLib = "System.Private.CoreLib"; + readonly AssemblyNameReference fixedCoreLib; + + public ILPostProcessorReflectionImporter(ModuleDefinition module) : base(module) + { + // find the correct library for "System.Private.CoreLib". + // either mscorlib or netstandard. + // defaults to System.Private.CoreLib if not found. + fixedCoreLib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == SystemPrivateCoreLib); + } + + public override AssemblyNameReference ImportReference(AssemblyName name) + { + // System.Private.CoreLib? + if (name.Name == SystemPrivateCoreLib && fixedCoreLib != null) + return fixedCoreLib; + + // otherwise import as usual + return base.ImportReference(name); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta new file mode 100644 index 0000000..40788da --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6403a7e3b3ae4e009ae282f111d266e0 +timeCreated: 1629709256 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporter.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs new file mode 100644 index 0000000..7358e1b --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs @@ -0,0 +1,16 @@ +// based on paul's resolver from +// https://github.com/MirageNet/Mirage/commit/def64cd1db525398738f057b3d1eb1fe8afc540c?branch=def64cd1db525398738f057b3d1eb1fe8afc540c&diff=split +// +// ILPostProcessorAssemblyRESOLVER does not find the .dll file for: +// "System.Private.CoreLib" +// we need this custom reflection importer to fix that. +using Mono.CecilX; + +namespace Mirror.Weaver +{ + internal class ILPostProcessorReflectionImporterProvider : IReflectionImporterProvider + { + public IReflectionImporter GetReflectionImporter(ModuleDefinition module) => + new ILPostProcessorReflectionImporter(module); + } +} diff --git a/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta new file mode 100644 index 0000000..ff5c4ca --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a1003b568bad4e69b961c4c81d5afd96 +timeCreated: 1629709223 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/EntryPointILPostProcessor/ILPostProcessorReflectionImporterProvider.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs b/Assets/Mirror/Editor/Weaver/Extensions.cs new file mode 100644 index 0000000..566a51a --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Extensions.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class Extensions + { + public static bool Is(this TypeReference td, Type type) => + type.IsGenericType + ? td.GetElementType().FullName == type.FullName + : td.FullName == type.FullName; + + // check if 'td' is exactly of type T. + // it does not check if any base type is of , only the specific type. + // for example: + // NetworkConnection Is NetworkConnection: true + // NetworkConnectionToClient Is NetworkConnection: false + public static bool Is(this TypeReference td) => Is(td, typeof(T)); + + // check if 'tr' is derived from T. + // it does not check if 'tr' is exactly T. + // for example: + // NetworkConnection IsDerivedFrom: false + // NetworkConnectionToClient IsDerivedFrom: true + public static bool IsDerivedFrom(this TypeReference tr) => IsDerivedFrom(tr, typeof(T)); + + public static bool IsDerivedFrom(this TypeReference tr, Type baseClass) + { + TypeDefinition td = tr.Resolve(); + if (!td.IsClass) + return false; + + // are ANY parent classes of baseClass? + TypeReference parent = td.BaseType; + + if (parent == null) + return false; + + if (parent.Is(baseClass)) + return true; + + if (parent.CanBeResolved()) + return IsDerivedFrom(parent.Resolve(), baseClass); + + return false; + } + + public static TypeReference GetEnumUnderlyingType(this TypeDefinition td) + { + foreach (FieldDefinition field in td.Fields) + { + if (!field.IsStatic) + return field.FieldType; + } + throw new ArgumentException($"Invalid enum {td.FullName}"); + } + + public static bool ImplementsInterface(this TypeDefinition td) + { + TypeDefinition typedef = td; + + while (typedef != null) + { + if (typedef.Interfaces.Any(iface => iface.InterfaceType.Is())) + return true; + + try + { + TypeReference parent = typedef.BaseType; + typedef = parent?.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); + break; + } + } + + return false; + } + + public static bool IsMultidimensionalArray(this TypeReference tr) => + tr is ArrayType arrayType && arrayType.Rank > 1; + + // Does type use netId as backing field + public static bool IsNetworkIdentityField(this TypeReference tr) => + tr.Is() || + tr.Is() || + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + tr.IsDerivedFrom() || + tr.Is(); + + public static bool CanBeResolved(this TypeReference parent) + { + while (parent != null) + { + if (parent.Scope.Name == "Windows") + { + return false; + } + + if (parent.Scope.Name == "mscorlib") + { + TypeDefinition resolved = parent.Resolve(); + return resolved != null; + } + + try + { + parent = parent.Resolve().BaseType; + } + catch + { + return false; + } + } + return true; + } + + // Makes T => Variable and imports function + public static MethodReference MakeGeneric(this MethodReference generic, ModuleDefinition module, TypeReference variableReference) + { + GenericInstanceMethod instance = new GenericInstanceMethod(generic); + instance.GenericArguments.Add(variableReference); + + MethodReference readFunc = module.ImportReference(instance); + return readFunc; + } + + // Given a method of a generic class such as ArraySegment`T.get_Count, + // and a generic instance such as ArraySegment`int + // Creates a reference to the specialized method ArraySegment`int`.get_Count + // Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + public static MethodReference MakeHostInstanceGeneric(this MethodReference self, ModuleDefinition module, GenericInstanceType instanceType) + { + MethodReference reference = new MethodReference(self.Name, self.ReturnType, instanceType) + { + CallingConvention = self.CallingConvention, + HasThis = self.HasThis, + ExplicitThis = self.ExplicitThis + }; + + foreach (ParameterDefinition parameter in self.Parameters) + reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); + + foreach (GenericParameter generic_parameter in self.GenericParameters) + reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference)); + + return module.ImportReference(reference); + } + + // needed for NetworkBehaviour support + // https://github.com/vis2k/Mirror/pull/3073/ + public static FieldReference MakeHostInstanceGeneric(this FieldReference self) + { + var declaringType = new GenericInstanceType(self.DeclaringType); + foreach (var parameter in self.DeclaringType.GenericParameters) + { + declaringType.GenericArguments.Add(parameter); + } + return new FieldReference(self.Name, self.FieldType, declaringType); + } + + // Given a field of a generic class such as Writer.write, + // and a generic instance such as ArraySegment`int + // Creates a reference to the specialized method ArraySegment`int`.get_Count + // Note that calling ArraySegment`T.get_Count directly gives an invalid IL error + public static FieldReference SpecializeField(this FieldReference self, ModuleDefinition module, GenericInstanceType instanceType) + { + FieldReference reference = new FieldReference(self.Name, self.FieldType, instanceType); + return module.ImportReference(reference); + } + + public static CustomAttribute GetCustomAttribute(this ICustomAttributeProvider method) + { + return method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Is()); + } + + public static bool HasCustomAttribute(this ICustomAttributeProvider attributeProvider) + { + return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is()); + } + + public static T GetField(this CustomAttribute ca, string field, T defaultValue) + { + foreach (CustomAttributeNamedArgument customField in ca.Fields) + if (customField.Name == field) + return (T)customField.Argument.Value; + return defaultValue; + } + + public static MethodDefinition GetMethod(this TypeDefinition td, string methodName) + { + return td.Methods.FirstOrDefault(method => method.Name == methodName); + } + + public static List GetMethods(this TypeDefinition td, string methodName) + { + return td.Methods.Where(method => method.Name == methodName).ToList(); + } + + public static MethodDefinition GetMethodInBaseType(this TypeDefinition td, string methodName) + { + TypeDefinition typedef = td; + while (typedef != null) + { + foreach (MethodDefinition md in typedef.Methods) + { + if (md.Name == methodName) + return md; + } + + try + { + TypeReference parent = typedef.BaseType; + typedef = parent?.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + break; + } + } + + return null; + } + + // Finds public fields in type and base type + public static IEnumerable FindAllPublicFields(this TypeReference variable) + { + return FindAllPublicFields(variable.Resolve()); + } + + // Finds public fields in type and base type + public static IEnumerable FindAllPublicFields(this TypeDefinition typeDefinition) + { + while (typeDefinition != null) + { + foreach (FieldDefinition field in typeDefinition.Fields) + { + // ignore static, private, protected fields + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3485 + // credit: James Frowen + if (field.IsStatic || field.IsPrivate || field.IsFamily) + continue; + + // also ignore internal fields + // we dont want to create different writers for this type if they are in current dll or another dll + // so we have to ignore internal in all cases + if (field.IsAssembly) + continue; + + if (field.IsNotSerialized) + continue; + + yield return field; + } + + try + { + typeDefinition = typeDefinition.BaseType?.Resolve(); + } + catch (AssemblyResolutionException) + { + break; + } + } + } + + public static bool ContainsClass(this ModuleDefinition module, string nameSpace, string className) => + module.GetTypes().Any(td => td.Namespace == nameSpace && + td.Name == className); + + + public static AssemblyNameReference FindReference(this ModuleDefinition module, string referenceName) + { + foreach (AssemblyNameReference reference in module.AssemblyReferences) + { + if (reference.Name == referenceName) + return reference; + } + return null; + } + + // Takes generic arguments from child class and applies them to parent reference, if possible + // eg makes `Base` in Child : Base have `int` instead of `T` + // Originally by James-Frowen under MIT + // https://github.com/MirageNet/Mirage/commit/cf91e1d54796866d2cf87f8e919bb5c681977e45 + public static TypeReference ApplyGenericParameters(this TypeReference parentReference, + TypeReference childReference) + { + // If the parent is not generic, we got nothing to apply + if (!parentReference.IsGenericInstance) + return parentReference; + + GenericInstanceType parentGeneric = (GenericInstanceType)parentReference; + // make new type so we can replace the args on it + // resolve it so we have non-generic instance (eg just instance with instead of ) + // if we don't cecil will make it double generic (eg INVALID IL) + GenericInstanceType generic = new GenericInstanceType(parentReference.Resolve()); + foreach (TypeReference arg in parentGeneric.GenericArguments) + generic.GenericArguments.Add(arg); + + for (int i = 0; i < generic.GenericArguments.Count; i++) + { + // if arg is not generic + // eg List would be int so not generic. + // But List would be T so is generic + if (!generic.GenericArguments[i].IsGenericParameter) + continue; + + // get the generic name, eg T + string name = generic.GenericArguments[i].Name; + // find what type T is, eg turn it into `int` if `List` + TypeReference arg = FindMatchingGenericArgument(childReference, name); + + // import just to be safe + TypeReference imported = parentReference.Module.ImportReference(arg); + // set arg on generic, parent ref will be Base instead of just Base + generic.GenericArguments[i] = imported; + } + + return generic; + } + + // Finds the type reference for a generic parameter with the provided name in the child reference + // Originally by James-Frowen under MIT + // https://github.com/MirageNet/Mirage/commit/cf91e1d54796866d2cf87f8e919bb5c681977e45 + static TypeReference FindMatchingGenericArgument(TypeReference childReference, string paramName) + { + TypeDefinition def = childReference.Resolve(); + // child class must be generic if we are in this part of the code + // eg Child : Base <--- child must have generic if Base has T + // vs Child : Base <--- wont be here if Base has int (we check if T exists before calling this) + if (!def.HasGenericParameters) + throw new InvalidOperationException( + "Base class had generic parameters, but could not find them in child class"); + + // go through parameters in child class, and find the generic that matches the name + for (int i = 0; i < def.GenericParameters.Count; i++) + { + GenericParameter param = def.GenericParameters[i]; + if (param.Name == paramName) + { + GenericInstanceType generic = (GenericInstanceType)childReference; + // return generic arg with same index + return generic.GenericArguments[i]; + } + } + + // this should never happen, if it does it means that this code is bugged + throw new InvalidOperationException("Did not find matching generic"); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs.meta b/Assets/Mirror/Editor/Weaver/Extensions.cs.meta new file mode 100644 index 0000000..d337f22 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Extensions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 562a5cf0254cc45738e9aa549a7100b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Extensions.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs b/Assets/Mirror/Editor/Weaver/Helpers.cs new file mode 100644 index 0000000..56b7385 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Helpers.cs @@ -0,0 +1,26 @@ +using System.IO; +using System.Linq; +using System.Reflection; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + static class Helpers + { + // This code is taken from SerializationWeaver + public static string UnityEngineDllDirectoryName() + { + string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); + return directoryName?.Replace(@"file:\", ""); + } + + public static bool IsEditorAssembly(AssemblyDefinition currentAssembly) + { + // we want to add the [InitializeOnLoad] attribute if it's available + // -> usually either 'UnityEditor' or 'UnityEditor.CoreModule' + return currentAssembly.MainModule.AssemblyReferences.Any(assemblyReference => + assemblyReference.Name.StartsWith(nameof(UnityEditor)) + ); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Helpers.cs.meta b/Assets/Mirror/Editor/Weaver/Helpers.cs.meta new file mode 100644 index 0000000..c8bf3d1 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Helpers.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6c4ed76daf48547c5abb7c58f8d20886 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Helpers.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Logger.cs b/Assets/Mirror/Editor/Weaver/Logger.cs new file mode 100644 index 0000000..8be978f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Logger.cs @@ -0,0 +1,13 @@ +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public interface Logger + { + void Warning(string message); + void Warning(string message, MemberReference mr); + void Error(string message); + void Error(string message, MemberReference mr); + } +} diff --git a/Assets/Mirror/Editor/Weaver/Logger.cs.meta b/Assets/Mirror/Editor/Weaver/Logger.cs.meta new file mode 100644 index 0000000..9aebf80 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Logger.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2a21c60c40a4c4d679c2b71a7c40882e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Logger.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors.meta b/Assets/Mirror/Editor/Weaver/Processors.meta new file mode 100644 index 0000000..eb719b4 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e538d627280d2471b8c72fdea822ca49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs new file mode 100644 index 0000000..db2d5af --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs @@ -0,0 +1,130 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [Command] methods in NetworkBehaviour + public static class CommandProcessor + { + /* + // generates code like: + public void CmdThrust(float thrusting, int spin) + { + NetworkWriterPooled writer = NetworkWriterPool.Get(); + writer.Write(thrusting); + writer.WritePackedUInt32((uint)spin); + base.SendCommandInternal(cmdName, cmdHash, writer, channel); + NetworkWriterPool.Return(writer); + } + + public void CallCmdThrust(float thrusting, int spin) + { + // whatever the user was doing before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to CmdTrust with CallCmdTrust + + This method moves all the user's code into the "CallCmd" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + */ + public static MethodDefinition ProcessCommandCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute commandAttr, ref bool WeavingFailed) + { + MethodDefinition cmd = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + // NetworkWriter writer = new NetworkWriter(); + NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the Cmd call + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.Command, ref WeavingFailed)) + return null; + + int channel = commandAttr.GetField("channel", 0); + bool requiresAuthority = commandAttr.GetField("requiresAuthority", true); + + // invoke internal send and return + // load 'base.' to call the SendCommand function with + worker.Emit(OpCodes.Ldarg_0); + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, channel); + // requiresAuthority ? 1 : 0 + worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Call, weaverTypes.sendCommandInternal); + + NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + return cmd; + } + + /* + // generates code like: + protected static void InvokeCmdCmdThrust(NetworkBehaviour obj, NetworkReader reader, NetworkConnection senderConnection) + { + if (!NetworkServer.active) + { + return; + } + ((ShipControl)obj).CmdThrust(reader.ReadSingle(), (int)reader.ReadPackedUInt32()); + } + */ + public static MethodDefinition ProcessCommandInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition method, MethodDefinition cmdCallFunc, ref bool WeavingFailed) + { + string cmdName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, method); + + MethodDefinition cmd = new MethodDefinition(cmdName, + MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = cmd.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteServerActiveCheck(worker, weaverTypes, method.Name, label, "Command"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + if (!NetworkBehaviourProcessor.ReadArguments(method, readers, Log, worker, RemoteCallType.Command, ref WeavingFailed)) + return null; + + AddSenderConnection(method, worker); + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, cmdCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, cmd.Parameters); + + td.Methods.Add(cmd); + return cmd; + } + + static void AddSenderConnection(MethodDefinition method, ILProcessor worker) + { + foreach (ParameterDefinition param in method.Parameters) + { + if (NetworkBehaviourProcessor.IsSenderConnection(param, RemoteCallType.Command)) + { + // NetworkConnection is 3nd arg (arg0 is "obj" not "this" because method is static) + // example: static void InvokeCmdCmdSendCommand(NetworkBehaviour obj, NetworkReader reader, NetworkConnection connection) + worker.Emit(OpCodes.Ldarg_2); + } + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta new file mode 100644 index 0000000..488c9c6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 73f6c9cdbb9e54f65b3a0a35cc8e55c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/CommandProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs new file mode 100644 index 0000000..8a4c581 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs @@ -0,0 +1,139 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class MethodProcessor + { + const string RpcPrefix = "UserCode_"; + + // For a function like + // [ClientRpc] void RpcTest(int value), + // Weaver substitutes the method and moves the code to a new method: + // UserCode_RpcTest(int value) <- contains original code + // RpcTest(int value) <- serializes parameters, sends the message + // + // Note that all the calls to the method remain untouched. + // FixRemoteCallToBaseMethod replaces them afterwards. + public static MethodDefinition SubstituteMethod(Logger Log, TypeDefinition td, MethodDefinition md, ref bool WeavingFailed) + { + string newName = Weaver.GenerateMethodName(RpcPrefix, md); + + MethodDefinition cmd = new MethodDefinition(newName, md.Attributes, md.ReturnType); + + // force the substitute method to be protected. + // -> public would show in the Inspector for UnityEvents as + // User_CmdUsePotion() etc. but the user shouldn't use those. + // -> private would not allow inheriting classes to call it, see + // OverrideVirtualWithBaseCallsBothVirtualAndBase test. + // -> IL has no concept of 'protected', it's called IsFamily there. + cmd.IsPublic = false; + cmd.IsFamily = true; + + // add parameters + foreach (ParameterDefinition pd in md.Parameters) + { + cmd.Parameters.Add(new ParameterDefinition(pd.Name, ParameterAttributes.None, pd.ParameterType)); + } + + // swap bodies + (cmd.Body, md.Body) = (md.Body, cmd.Body); + + // Move over all the debugging information + foreach (SequencePoint sequencePoint in md.DebugInformation.SequencePoints) + cmd.DebugInformation.SequencePoints.Add(sequencePoint); + md.DebugInformation.SequencePoints.Clear(); + + foreach (CustomDebugInformation customInfo in md.CustomDebugInformations) + cmd.CustomDebugInformations.Add(customInfo); + md.CustomDebugInformations.Clear(); + + (md.DebugInformation.Scope, cmd.DebugInformation.Scope) = (cmd.DebugInformation.Scope, md.DebugInformation.Scope); + + td.Methods.Add(cmd); + + FixRemoteCallToBaseMethod(Log, td, cmd, ref WeavingFailed); + return cmd; + } + + // For a function like + // [ClientRpc] void RpcTest(int value), + // Weaver substitutes the method and moves the code to a new method: + // UserCode_RpcTest(int value) <- contains original code + // RpcTest(int value) <- serializes parameters, sends the message + // + // FixRemoteCallToBaseMethod replaces all calls to + // RpcTest(value) + // with + // UserCode_RpcTest(value) + public static void FixRemoteCallToBaseMethod(Logger Log, TypeDefinition type, MethodDefinition method, ref bool WeavingFailed) + { + string callName = method.Name; + + // Cmd/rpc start with Weaver.RpcPrefix + // e.g. CallCmdDoSomething + if (!callName.StartsWith(RpcPrefix)) + return; + + // e.g. CmdDoSomething + string baseRemoteCallName = method.Name.Substring(RpcPrefix.Length); + + foreach (Instruction instruction in method.Body.Instructions) + { + // is this instruction a Call to a method? + // if yes, output the method so we can check it. + if (IsCallToMethod(instruction, out MethodDefinition calledMethod)) + { + // when considering if 'calledMethod' is a call to 'method', + // we originally compared .Name. + // + // to fix IL2CPP build bugs with overloaded Rpcs, we need to + // generated rpc names like + // RpcTest(string value) => RpcTestString(strig value) + // RpcTest(int value) => RpcTestInt(int value) + // to make them unique. + // + // calledMethod.Name is still "RpcTest", so we need to + // convert this to the generated name as well before comparing. + string calledMethodName_Generated = Weaver.GenerateMethodName("", calledMethod); + if (calledMethodName_Generated == baseRemoteCallName) + { + TypeDefinition baseType = type.BaseType.Resolve(); + MethodDefinition baseMethod = baseType.GetMethodInBaseType(callName); + + if (baseMethod == null) + { + Log.Error($"Could not find base method for {callName}", method); + WeavingFailed = true; + return; + } + + if (!baseMethod.IsVirtual) + { + Log.Error($"Could not find base method that was virtual {callName}", method); + WeavingFailed = true; + return; + } + + instruction.Operand = baseMethod; + } + } + } + } + + static bool IsCallToMethod(Instruction instruction, out MethodDefinition calledMethod) + { + if (instruction.OpCode == OpCodes.Call && + instruction.Operand is MethodDefinition method) + { + calledMethod = method; + return true; + } + else + { + calledMethod = null; + return false; + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta new file mode 100644 index 0000000..9cbd357 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 661e1af528e3441f79e1552fb5ec4e0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/MethodProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs new file mode 100644 index 0000000..e88c5d6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs @@ -0,0 +1,56 @@ +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // only shows warnings in case we use SyncVars etc. for MonoBehaviour. + static class MonoBehaviourProcessor + { + public static void Process(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + ProcessSyncVars(Log, td, ref WeavingFailed); + ProcessMethods(Log, td, ref WeavingFailed); + } + + static void ProcessSyncVars(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + // find syncvars + foreach (FieldDefinition fd in td.Fields) + { + if (fd.HasCustomAttribute()) + { + Log.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); + WeavingFailed = true; + } + + if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) + { + Log.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); + WeavingFailed = true; + } + } + } + + static void ProcessMethods(Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + // find command and RPC functions + foreach (MethodDefinition md in td.Methods) + { + if (md.HasCustomAttribute()) + { + Log.Error($"Command {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + if (md.HasCustomAttribute()) + { + Log.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + if (md.HasCustomAttribute()) + { + Log.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md); + WeavingFailed = true; + } + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta new file mode 100644 index 0000000..154c73e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 35c16722912b64af894e4f6668f2e54c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/MonoBehaviourProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs new file mode 100644 index 0000000..47f1b94 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs @@ -0,0 +1,1055 @@ +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public enum RemoteCallType + { + Command, + ClientRpc, + TargetRpc + } + + // processes SyncVars, Cmds, Rpcs, etc. of NetworkBehaviours + class NetworkBehaviourProcessor + { + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + SyncVarAccessLists syncVarAccessLists; + SyncVarAttributeProcessor syncVarAttributeProcessor; + Writers writers; + Readers readers; + Logger Log; + + List syncVars = new List(); + List syncObjects = new List(); + // + Dictionary syncVarNetIds = new Dictionary(); + // - Every syncvar with a hook has a new field created to store the Action delegate so we don't allocate on every hook invocation + // This dictionary maps each syncvar field to the field that will store the hook method delegate instance, and the method from which the delegate instance is constructed from + Dictionary syncVarHookDelegates = new Dictionary(); + readonly List commands = new List(); + readonly List clientRpcs = new List(); + readonly List targetRpcs = new List(); + readonly List commandInvocationFuncs = new List(); + readonly List clientRpcInvocationFuncs = new List(); + readonly List targetRpcInvocationFuncs = new List(); + + readonly TypeDefinition netBehaviourSubclass; + + public struct CmdResult + { + public MethodDefinition method; + public bool requiresAuthority; + } + + public struct ClientRpcResult + { + public MethodDefinition method; + public bool includeOwner; + } + + public NetworkBehaviourProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, SyncVarAccessLists syncVarAccessLists, Writers writers, Readers readers, Logger Log, TypeDefinition td) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.syncVarAccessLists = syncVarAccessLists; + this.writers = writers; + this.readers = readers; + this.Log = Log; + syncVarAttributeProcessor = new SyncVarAttributeProcessor(assembly, weaverTypes, syncVarAccessLists, Log); + netBehaviourSubclass = td; + } + + // return true if modified + public bool Process(ref bool WeavingFailed) + { + // only process once + if (WasProcessed(netBehaviourSubclass)) + { + return false; + } + + MarkAsProcessed(netBehaviourSubclass); + + // deconstruct tuple and set fields + (syncVars, syncVarNetIds, syncVarHookDelegates) = syncVarAttributeProcessor.ProcessSyncVars(netBehaviourSubclass, ref WeavingFailed); + + syncObjects = SyncObjectProcessor.FindSyncObjectsFields(writers, readers, Log, netBehaviourSubclass, ref WeavingFailed); + + ProcessMethods(ref WeavingFailed); + if (WeavingFailed) + { + // originally Process returned true in every case, except if already processed. + // maybe return false here in the future. + return true; + } + + // inject initializations into static & instance constructor + InjectIntoStaticConstructor(ref WeavingFailed); + InjectIntoInstanceConstructor(ref WeavingFailed); + + GenerateSerialization(ref WeavingFailed); + if (WeavingFailed) + { + // originally Process returned true in every case, except if already processed. + // maybe return false here in the future. + return true; + } + + GenerateDeSerialization(ref WeavingFailed); + return true; + } + + /* + generates code like: + if (!NetworkClient.active) + Debug.LogError((object) "Command function CmdRespawn called on server."); + + which is used in InvokeCmd, InvokeRpc, etc. + */ + public static void WriteClientActiveCheck(ILProcessor worker, WeaverTypes weaverTypes, string mdName, Instruction label, string errString) + { + // client active check + worker.Emit(OpCodes.Call, weaverTypes.NetworkClientGetActive); + worker.Emit(OpCodes.Brtrue, label); + + worker.Emit(OpCodes.Ldstr, $"{errString} {mdName} called on server."); + worker.Emit(OpCodes.Call, weaverTypes.logErrorReference); + worker.Emit(OpCodes.Ret); + worker.Append(label); + } + /* + generates code like: + if (!NetworkServer.active) + Debug.LogError((object) "Command CmdMsgWhisper called on client."); + */ + public static void WriteServerActiveCheck(ILProcessor worker, WeaverTypes weaverTypes, string mdName, Instruction label, string errString) + { + // server active check + worker.Emit(OpCodes.Call, weaverTypes.NetworkServerGetActive); + worker.Emit(OpCodes.Brtrue, label); + + worker.Emit(OpCodes.Ldstr, $"{errString} {mdName} called on client."); + worker.Emit(OpCodes.Call, weaverTypes.logErrorReference); + worker.Emit(OpCodes.Ret); + worker.Append(label); + } + + public static void WriteSetupLocals(ILProcessor worker, WeaverTypes weaverTypes) + { + worker.Body.InitLocals = true; + worker.Body.Variables.Add(new VariableDefinition(weaverTypes.Import())); + } + + public static void WriteGetWriter(ILProcessor worker, WeaverTypes weaverTypes) + { + // create writer + worker.Emit(OpCodes.Call, weaverTypes.GetWriterReference); + worker.Emit(OpCodes.Stloc_0); + } + + public static void WriteReturnWriter(ILProcessor worker, WeaverTypes weaverTypes) + { + // NetworkWriterPool.Recycle(writer); + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Call, weaverTypes.ReturnWriterReference); + } + + public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Log, MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed) + { + // write each argument + // example result + /* + writer.WritePackedInt32(someNumber); + writer.WriteNetworkIdentity(someTarget); + */ + + bool skipFirst = callType == RemoteCallType.TargetRpc + && TargetRpcProcessor.HasNetworkConnectionParameter(method); + + // arg of calling function, arg 0 is "this" so start counting at 1 + int argNum = 1; + foreach (ParameterDefinition param in method.Parameters) + { + // NetworkConnection is not sent via the NetworkWriter so skip it here + // skip first for NetworkConnection in TargetRpc + if (argNum == 1 && skipFirst) + { + argNum += 1; + continue; + } + // skip SenderConnection in Command + if (IsSenderConnection(param, callType)) + { + argNum += 1; + continue; + } + + MethodReference writeFunc = writers.GetWriteFunc(param.ParameterType, ref WeavingFailed); + if (writeFunc == null) + { + Log.Error($"{method.Name} has invalid parameter {param}", method); + WeavingFailed = true; + return false; + } + + // use built-in writer func on writer object + // NetworkWriter object + worker.Emit(OpCodes.Ldloc_0); + // add argument to call + worker.Emit(OpCodes.Ldarg, argNum); + // call writer extension method + worker.Emit(OpCodes.Call, writeFunc); + argNum += 1; + } + return true; + } + + #region mark / check type as processed + public const string ProcessedFunctionName = "Weaved"; + + // check if the type has a "Weaved" function already + public static bool WasProcessed(TypeDefinition td) + { + return td.GetMethod(ProcessedFunctionName) != null; + } + + // add the Weaved() function which returns true. + // can be called at runtime and from tests to check if weaving succeeded. + public void MarkAsProcessed(TypeDefinition td) + { + if (!WasProcessed(td)) + { + // add a function: + // public override bool MirrorProcessed() { return true; } + // ReuseSlot means 'override'. + MethodDefinition versionMethod = new MethodDefinition( + ProcessedFunctionName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, + weaverTypes.Import(typeof(bool))); + ILProcessor worker = versionMethod.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldc_I4_1); + worker.Emit(OpCodes.Ret); + td.Methods.Add(versionMethod); + } + } + #endregion + + // helper function to remove 'Ret' from the end of the method if 'Ret' + // is the last instruction. + // returns false if there was an issue + static bool RemoveFinalRetInstruction(MethodDefinition method) + { + // remove the return opcode from end of function. will add our own later. + if (method.Body.Instructions.Count != 0) + { + Instruction retInstr = method.Body.Instructions[method.Body.Instructions.Count - 1]; + if (retInstr.OpCode == OpCodes.Ret) + { + method.Body.Instructions.RemoveAt(method.Body.Instructions.Count - 1); + return true; + } + return false; + } + + // we did nothing, but there was no error. + return true; + } + + // we need to inject several initializations into NetworkBehaviour cctor + void InjectIntoStaticConstructor(ref bool WeavingFailed) + { + if (commands.Count == 0 && clientRpcs.Count == 0 && targetRpcs.Count == 0) + return; + + // find static constructor + MethodDefinition cctor = netBehaviourSubclass.GetMethod(".cctor"); + bool cctorFound = cctor != null; + if (cctor != null) + { + // remove the return opcode from end of function. will add our own later. + if (!RemoveFinalRetInstruction(cctor)) + { + Log.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor); + WeavingFailed = true; + return; + } + } + else + { + // make one! + cctor = new MethodDefinition(".cctor", MethodAttributes.Private | + MethodAttributes.HideBySig | + MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName | + MethodAttributes.Static, + weaverTypes.Import(typeof(void))); + } + + ILProcessor cctorWorker = cctor.Body.GetILProcessor(); + + // register all commands in cctor + for (int i = 0; i < commands.Count; ++i) + { + CmdResult cmdResult = commands[i]; + GenerateRegisterCommandDelegate(cctorWorker, weaverTypes.registerCommandReference, commandInvocationFuncs[i], cmdResult); + } + + // register all client rpcs in cctor + for (int i = 0; i < clientRpcs.Count; ++i) + { + ClientRpcResult clientRpcResult = clientRpcs[i]; + GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes.registerRpcReference, clientRpcInvocationFuncs[i], clientRpcResult.method.FullName); + } + + // register all target rpcs in cctor + for (int i = 0; i < targetRpcs.Count; ++i) + { + GenerateRegisterRemoteDelegate(cctorWorker, weaverTypes.registerRpcReference, targetRpcInvocationFuncs[i], targetRpcs[i].FullName); + } + + // add final 'Ret' instruction to cctor + cctorWorker.Append(cctorWorker.Create(OpCodes.Ret)); + if (!cctorFound) + { + netBehaviourSubclass.Methods.Add(cctor); + } + + // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late + netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit; + } + + // we need to inject several initializations into NetworkBehaviour ctor + void InjectIntoInstanceConstructor(ref bool WeavingFailed) + { + if ((syncObjects.Count == 0) && (syncVarHookDelegates.Count == 0)) + return; + + // find instance constructor + MethodDefinition ctor = netBehaviourSubclass.GetMethod(".ctor"); + if (ctor == null) + { + Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass); + WeavingFailed = true; + return; + } + + // remove the return opcode from end of function. will add our own later. + if (!RemoveFinalRetInstruction(ctor)) + { + Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor); + WeavingFailed = true; + return; + } + + ILProcessor ctorWorker = ctor.Body.GetILProcessor(); + + // initialize all sync objects in ctor + foreach (FieldDefinition fd in syncObjects) + { + SyncObjectInitializer.GenerateSyncObjectInitializer(ctorWorker, weaverTypes, fd); + } + + // initialize all delegate fields in ctor + foreach(KeyValuePair entry in syncVarHookDelegates) + { + FieldDefinition syncVarField = entry.Key; + (FieldDefinition hookDelegate, MethodDefinition hookMethod) = entry.Value; + syncVarAttributeProcessor.GenerateSyncVarHookDelegateInitializer(ctorWorker, syncVarField, hookDelegate, hookMethod); + } + + // add final 'Ret' instruction to ctor + ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); + } + + /* + // This generates code like: + NetworkBehaviour.RegisterCommandDelegate(base.GetType(), "CmdThrust", new NetworkBehaviour.CmdDelegate(ShipControl.InvokeCmdCmdThrust)); + */ + + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + void GenerateRegisterRemoteDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, string functionFullName) + { + worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass); + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, functionFullName); + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, func); + + worker.Emit(OpCodes.Newobj, weaverTypes.RemoteCallDelegateConstructor); + // + worker.Emit(OpCodes.Call, registerMethod); + } + + void GenerateRegisterCommandDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, CmdResult cmdResult) + { + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + string cmdName = cmdResult.method.FullName; + bool requiresAuthority = cmdResult.requiresAuthority; + + worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass); + worker.Emit(OpCodes.Call, weaverTypes.getTypeFromHandleReference); + worker.Emit(OpCodes.Ldstr, cmdName); + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, func); + + worker.Emit(OpCodes.Newobj, weaverTypes.RemoteCallDelegateConstructor); + + // requiresAuthority ? 1 : 0 + worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + + worker.Emit(OpCodes.Call, registerMethod); + } + + void GenerateSerialization(ref bool WeavingFailed) + { + const string SerializeMethodName = "SerializeSyncVars"; + if (netBehaviourSubclass.GetMethod(SerializeMethodName) != null) + return; + + if (syncVars.Count == 0) + { + // no synvars, no need for custom OnSerialize + return; + } + + MethodDefinition serialize = new MethodDefinition(SerializeMethodName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import())); + serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, weaverTypes.Import())); + ILProcessor worker = serialize.Body.GetILProcessor(); + + serialize.Body.InitLocals = true; + + // base.SerializeSyncVars(writer, forceAll); + MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, SerializeMethodName); + if (baseSerialize != null) + { + // base + worker.Emit(OpCodes.Ldarg_0); + // writer + worker.Emit(OpCodes.Ldarg_1); + // forceAll + worker.Emit(OpCodes.Ldarg_2); + worker.Emit(OpCodes.Call, baseSerialize); + } + + // Generates: + // if (forceAll) + // { + // writer.WriteInt(health); + // ... + // } + Instruction initialStateLabel = worker.Create(OpCodes.Nop); + // forceAll + worker.Emit(OpCodes.Ldarg_2); // load 'forceAll' flag + worker.Emit(OpCodes.Brfalse, initialStateLabel); // start the 'if forceAll' branch + + // generates write.Write(syncVar) for each SyncVar in forceAll case + foreach (FieldDefinition syncVarDef in syncVars) + { + FieldReference syncVar = syncVarDef; + if (netBehaviourSubclass.HasGenericParameters) + { + syncVar = syncVarDef.MakeHostInstanceGeneric(); + } + // Generates a writer call for each sync variable + // writer + worker.Emit(OpCodes.Ldarg_1); + // this + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + MethodReference writeFunc; + // For NBs we always need to use the default NetworkBehaviour write func + // since the reader counter part uses that exact layout which is not easy to change + // without introducing more edge cases + // effectively this disallows custom NB-type writers/readers on SyncVars + // see: https://github.com/MirrorNetworking/Mirror/issues/2680 + if (syncVar.FieldType.IsDerivedFrom()) + { + writeFunc = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + } + else + { + writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + } + + if (writeFunc != null) + { + worker.Emit(OpCodes.Call, writeFunc); + } + else + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + } + + // if (forceAll) then always return at the end of the 'if' case + worker.Emit(OpCodes.Ret); + + // end the 'if' case for "if (forceAll)" + worker.Append(initialStateLabel); + + //////////////////////////////////////////////////////////////////// + + // write dirty bits before the data fields + // Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ()); + // writer + worker.Emit(OpCodes.Ldarg_1); + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, weaverTypes.NetworkBehaviourDirtyBitsReference); + MethodReference writeUint64Func = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + worker.Emit(OpCodes.Call, writeUint64Func); + + // generate a writer call for any dirty variable in this class + + // start at number of syncvars in parent + int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); + foreach (FieldDefinition syncVarDef in syncVars) + { + FieldReference syncVar = syncVarDef; + if (netBehaviourSubclass.HasGenericParameters) + { + syncVar = syncVarDef.MakeHostInstanceGeneric(); + } + Instruction varLabel = worker.Create(OpCodes.Nop); + + // Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL) + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, weaverTypes.NetworkBehaviourDirtyBitsReference); + // 8 bytes = long + worker.Emit(OpCodes.Ldc_I8, 1L << dirtyBit); + worker.Emit(OpCodes.And); + worker.Emit(OpCodes.Brfalse, varLabel); + + // Generates a call to the writer for that field + // writer + worker.Emit(OpCodes.Ldarg_1); + // base + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, syncVar); + + MethodReference writeFunc; + // For NBs we always need to use the default NetworkBehaviour write func + // since the reader counter part uses that exact layout which is not easy to change + // without introducing more edge cases + // effectively this disallows custom NB-type writers/readers on SyncVars + // see: https://github.com/MirrorNetworking/Mirror/issues/2680 + if (syncVar.FieldType.IsDerivedFrom()) + { + writeFunc = writers.GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + } + else + { + writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed); + } + + if (writeFunc != null) + { + worker.Emit(OpCodes.Call, writeFunc); + } + else + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + + worker.Append(varLabel); + dirtyBit += 1; + } + + // add a log message if needed for debugging + //worker.Emit(OpCodes.Ldstr, $"Injected Serialize {netBehaviourSubclass.Name}"); + //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference); + + // generate: return + worker.Emit(OpCodes.Ret); + netBehaviourSubclass.Methods.Add(serialize); + } + + void DeserializeField(FieldDefinition syncVar, ILProcessor worker, ref bool WeavingFailed) + { + // put 'this.' onto stack for 'this.syncvar' below + worker.Append(worker.Create(OpCodes.Ldarg_0)); + + // push 'ref T this.field' + worker.Emit(OpCodes.Ldarg_0); + // if the netbehaviour class is generic, we need to make the field reference generic as well for correct IL + if (netBehaviourSubclass.HasGenericParameters) + { + worker.Emit(OpCodes.Ldflda, syncVar.MakeHostInstanceGeneric()); + } + else + { + worker.Emit(OpCodes.Ldflda, syncVar); + } + + // If a hook exists, then we need to load the hook delegate on the stack + // The hook delegate is created once in the constructor and stored in an instance field + // We load the delegate from this instance field to avoid instantiating a new delegate instance every time (drastically reduces allocations) + if(syncVarHookDelegates.TryGetValue(syncVar, out (FieldDefinition hookDelegateField, MethodDefinition) value)) + { + // A hook exists. Push this.hookDelegateField onto the stack + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, value.hookDelegateField); + } + else + { + // No hook exists. Push 'null' as hook + worker.Emit(OpCodes.Ldnull); + } + + // call GeneratedSyncVarDeserialize. + // special cases for GameObject/NetworkIdentity/NetworkBehaviour + // passing netId too for persistence. + if (syncVar.FieldType.Is()) + { + // reader + worker.Emit(OpCodes.Ldarg_1); + + // GameObject setter needs one more parameter: netId field ref + FieldDefinition netIdField = syncVarNetIds[syncVar]; + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdField); + worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_GameObject); + } + else if (syncVar.FieldType.Is()) + { + // reader + worker.Emit(OpCodes.Ldarg_1); + + // NetworkIdentity deserialize needs one more parameter: netId field ref + FieldDefinition netIdField = syncVarNetIds[syncVar]; + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdField); + worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity); + } + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (syncVar.FieldType.IsDerivedFrom() || syncVar.FieldType.Is()) + { + // reader + worker.Emit(OpCodes.Ldarg_1); + + // NetworkIdentity deserialize needs one more parameter: netId field ref + // (actually its a NetworkBehaviourSyncVar type) + FieldDefinition netIdField = syncVarNetIds[syncVar]; + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdField); + // make generic version of GeneratedSyncVarSetter_NetworkBehaviour + MethodReference getFunc = weaverTypes.generatedSyncVarDeserialize_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, syncVar.FieldType); + worker.Emit(OpCodes.Call, getFunc); + } + else + { + // T value = reader.ReadT(); + // this is still in IL because otherwise weaver generated + // readers/writers don't seem to work in tests. + // besides, this also avoids reader.Read overhead. + MethodReference readFunc = readers.GetReadFunc(syncVar.FieldType, ref WeavingFailed); + if (readFunc == null) + { + Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar); + WeavingFailed = true; + return; + } + // reader. for 'reader.Read()' below + worker.Emit(OpCodes.Ldarg_1); + // reader.Read() + worker.Emit(OpCodes.Call, readFunc); + + // make generic version of GeneratedSyncVarDeserialize + MethodReference generic = weaverTypes.generatedSyncVarDeserialize.MakeGeneric(assembly.MainModule, syncVar.FieldType); + worker.Emit(OpCodes.Call, generic); + } + } + + void GenerateDeSerialization(ref bool WeavingFailed) + { + const string DeserializeMethodName = "DeserializeSyncVars"; + if (netBehaviourSubclass.GetMethod(DeserializeMethodName) != null) + return; + + if (syncVars.Count == 0) + { + // no synvars, no need for custom OnDeserialize + return; + } + + MethodDefinition serialize = new MethodDefinition(DeserializeMethodName, + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + serialize.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + serialize.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, weaverTypes.Import())); + ILProcessor serWorker = serialize.Body.GetILProcessor(); + // setup local for dirty bits + serialize.Body.InitLocals = true; + VariableDefinition dirtyBitsLocal = new VariableDefinition(weaverTypes.Import()); + serialize.Body.Variables.Add(dirtyBitsLocal); + + MethodReference baseDeserialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, DeserializeMethodName); + if (baseDeserialize != null) + { + // base + serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); + // reader + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + // initialState + serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); + serWorker.Append(serWorker.Create(OpCodes.Call, baseDeserialize)); + } + + // Generates: if (initialState); + Instruction initialStateLabel = serWorker.Create(OpCodes.Nop); + + serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); + serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel)); + + foreach (FieldDefinition syncVar in syncVars) + { + DeserializeField(syncVar, serWorker, ref WeavingFailed); + } + + serWorker.Append(serWorker.Create(OpCodes.Ret)); + + // Generates: end if (initialState); + serWorker.Append(initialStateLabel); + + // get dirty bits + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + serWorker.Append(serWorker.Create(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import(), ref WeavingFailed))); + serWorker.Append(serWorker.Create(OpCodes.Stloc_0)); + + // conditionally read each syncvar + // start at number of syncvars in parent + int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName); + foreach (FieldDefinition syncVar in syncVars) + { + Instruction varLabel = serWorker.Create(OpCodes.Nop); + + // check if dirty bit is set + serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); + serWorker.Append(serWorker.Create(OpCodes.Ldc_I8, 1L << dirtyBit)); + serWorker.Append(serWorker.Create(OpCodes.And)); + serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel)); + + DeserializeField(syncVar, serWorker, ref WeavingFailed); + + serWorker.Append(varLabel); + dirtyBit += 1; + } + + // add a log message if needed for debugging + //serWorker.Append(serWorker.Create(OpCodes.Ldstr, $"Injected Deserialize {netBehaviourSubclass.Name}")); + //serWorker.Append(serWorker.Create(OpCodes.Call, WeaverTypes.logErrorReference)); + + serWorker.Append(serWorker.Create(OpCodes.Ret)); + netBehaviourSubclass.Methods.Add(serialize); + } + + public static bool ReadArguments(MethodDefinition method, Readers readers, Logger Log, ILProcessor worker, RemoteCallType callType, ref bool WeavingFailed) + { + // read each argument + // example result + /* + CallCmdDoSomething(reader.ReadPackedInt32(), reader.ReadNetworkIdentity()); + */ + + bool skipFirst = callType == RemoteCallType.TargetRpc + && TargetRpcProcessor.HasNetworkConnectionParameter(method); + + // arg of calling function, arg 0 is "this" so start counting at 1 + int argNum = 1; + foreach (ParameterDefinition param in method.Parameters) + { + // NetworkConnection is not sent via the NetworkWriter so skip it here + // skip first for NetworkConnection in TargetRpc + if (argNum == 1 && skipFirst) + { + argNum += 1; + continue; + } + // skip SenderConnection in Command + if (IsSenderConnection(param, callType)) + { + argNum += 1; + continue; + } + + + MethodReference readFunc = readers.GetReadFunc(param.ParameterType, ref WeavingFailed); + + if (readFunc == null) + { + Log.Error($"{method.Name} has invalid parameter {param}. Unsupported type {param.ParameterType}, use a supported Mirror type instead", method); + WeavingFailed = true; + return false; + } + + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Call, readFunc); + + // conversion.. is this needed? + if (param.ParameterType.Is()) + { + worker.Emit(OpCodes.Conv_R4); + } + else if (param.ParameterType.Is()) + { + worker.Emit(OpCodes.Conv_R8); + } + } + return true; + } + + public static void AddInvokeParameters(WeaverTypes weaverTypes, ICollection collection) + { + collection.Add(new ParameterDefinition("obj", ParameterAttributes.None, weaverTypes.Import())); + collection.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + // senderConnection is only used for commands but NetworkBehaviour.CmdDelegate is used for all remote calls + collection.Add(new ParameterDefinition("senderConnection", ParameterAttributes.None, weaverTypes.Import())); + } + + // check if a Command/TargetRpc/Rpc function & parameters are valid for weaving + public bool ValidateRemoteCallAndParameters(MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed) + { + if (method.IsStatic) + { + Log.Error($"{method.Name} must not be static", method); + WeavingFailed = true; + return false; + } + + return ValidateFunction(method, ref WeavingFailed) && + ValidateParameters(method, callType, ref WeavingFailed); + } + + // check if a Command/TargetRpc/Rpc function is valid for weaving + bool ValidateFunction(MethodReference md, ref bool WeavingFailed) + { + if (md.ReturnType.Is()) + { + Log.Error($"{md.Name} cannot be a coroutine", md); + WeavingFailed = true; + return false; + } + if (!md.ReturnType.Is(typeof(void))) + { + Log.Error($"{md.Name} cannot return a value. Make it void instead", md); + WeavingFailed = true; + return false; + } + if (md.HasGenericParameters) + { + Log.Error($"{md.Name} cannot have generic parameters", md); + WeavingFailed = true; + return false; + } + return true; + } + + // check if all Command/TargetRpc/Rpc function's parameters are valid for weaving + bool ValidateParameters(MethodReference method, RemoteCallType callType, ref bool WeavingFailed) + { + for (int i = 0; i < method.Parameters.Count; ++i) + { + ParameterDefinition param = method.Parameters[i]; + if (!ValidateParameter(method, param, callType, i == 0, ref WeavingFailed)) + { + return false; + } + } + return true; + } + + // validate parameters for a remote function call like Rpc/Cmd + bool ValidateParameter(MethodReference method, ParameterDefinition param, RemoteCallType callType, bool firstParam, ref bool WeavingFailed) + { + // need to check this before any type lookups since those will fail since generic types don't resolve + if (param.ParameterType.IsGenericParameter) + { + Log.Error($"{method.Name} cannot have generic parameters", method); + WeavingFailed = true; + return false; + } + + bool isNetworkConnection = param.ParameterType.Is(); + bool isSenderConnection = IsSenderConnection(param, callType); + + if (param.IsOut) + { + Log.Error($"{method.Name} cannot have out parameters", method); + WeavingFailed = true; + return false; + } + + // if not SenderConnection And not TargetRpc NetworkConnection first param + if (!isSenderConnection && isNetworkConnection && !(callType == RemoteCallType.TargetRpc && firstParam)) + { + if (callType == RemoteCallType.Command) + { + Log.Error($"{method.Name} has invalid parameter {param}, Cannot pass NetworkConnections. Instead use 'NetworkConnectionToClient conn = null' to get the sender's connection on the server", method); + } + else + { + Log.Error($"{method.Name} has invalid parameter {param}. Cannot pass NetworkConnections", method); + } + WeavingFailed = true; + return false; + } + + // sender connection can be optional + if (param.IsOptional && !isSenderConnection) + { + Log.Error($"{method.Name} cannot have optional parameters", method); + WeavingFailed = true; + return false; + } + + return true; + } + + public static bool IsSenderConnection(ParameterDefinition param, RemoteCallType callType) + { + if (callType != RemoteCallType.Command) + { + return false; + } + + TypeReference type = param.ParameterType; + + return type.Is() + || type.Resolve().IsDerivedFrom(); + } + + void ProcessMethods(ref bool WeavingFailed) + { + HashSet names = new HashSet(); + + // copy the list of methods because we will be adding methods in the loop + List methods = new List(netBehaviourSubclass.Methods); + // find command and RPC functions + foreach (MethodDefinition md in methods) + { + foreach (CustomAttribute ca in md.CustomAttributes) + { + if (ca.AttributeType.Is()) + { + ProcessCommand(names, md, ca, ref WeavingFailed); + break; + } + + if (ca.AttributeType.Is()) + { + ProcessTargetRpc(names, md, ca, ref WeavingFailed); + break; + } + + if (ca.AttributeType.Is()) + { + ProcessClientRpc(names, md, ca, ref WeavingFailed); + break; + } + } + } + } + + void ProcessClientRpc(HashSet names, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract ClientRpc are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.ClientRpc, ref WeavingFailed)) + { + return; + } + + bool includeOwner = clientRpcAttr.GetField("includeOwner", true); + + names.Add(md.Name); + clientRpcs.Add(new ClientRpcResult + { + method = md, + includeOwner = includeOwner + }); + + MethodDefinition rpcCallFunc = RpcProcessor.ProcessRpcCall(weaverTypes, writers, Log, netBehaviourSubclass, md, clientRpcAttr, ref WeavingFailed); + // need null check here because ProcessRpcCall returns null if it can't write all the args + if (rpcCallFunc == null) { return; } + + MethodDefinition rpcFunc = RpcProcessor.ProcessRpcInvoke(weaverTypes, writers, readers, Log, netBehaviourSubclass, md, rpcCallFunc, ref WeavingFailed); + if (rpcFunc != null) + { + clientRpcInvocationFuncs.Add(rpcFunc); + } + } + + void ProcessTargetRpc(HashSet names, MethodDefinition md, CustomAttribute targetRpcAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract TargetRpc are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.TargetRpc, ref WeavingFailed)) + return; + + names.Add(md.Name); + targetRpcs.Add(md); + + MethodDefinition rpcCallFunc = TargetRpcProcessor.ProcessTargetRpcCall(weaverTypes, writers, Log, netBehaviourSubclass, md, targetRpcAttr, ref WeavingFailed); + + MethodDefinition rpcFunc = TargetRpcProcessor.ProcessTargetRpcInvoke(weaverTypes, readers, Log, netBehaviourSubclass, md, rpcCallFunc, ref WeavingFailed); + if (rpcFunc != null) + { + targetRpcInvocationFuncs.Add(rpcFunc); + } + } + + void ProcessCommand(HashSet names, MethodDefinition md, CustomAttribute commandAttr, ref bool WeavingFailed) + { + if (md.IsAbstract) + { + Log.Error("Abstract Commands are currently not supported, use virtual method instead", md); + WeavingFailed = true; + return; + } + + if (!ValidateRemoteCallAndParameters(md, RemoteCallType.Command, ref WeavingFailed)) + return; + + bool requiresAuthority = commandAttr.GetField("requiresAuthority", true); + + names.Add(md.Name); + commands.Add(new CmdResult + { + method = md, + requiresAuthority = requiresAuthority + }); + + MethodDefinition cmdCallFunc = CommandProcessor.ProcessCommandCall(weaverTypes, writers, Log, netBehaviourSubclass, md, commandAttr, ref WeavingFailed); + + MethodDefinition cmdFunc = CommandProcessor.ProcessCommandInvoke(weaverTypes, readers, Log, netBehaviourSubclass, md, cmdCallFunc, ref WeavingFailed); + if (cmdFunc != null) + { + commandInvocationFuncs.Add(cmdFunc); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta new file mode 100644 index 0000000..a48253f --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8118d606be3214e5d99943ec39530dd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/NetworkBehaviourProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs new file mode 100644 index 0000000..2a919d2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs @@ -0,0 +1,260 @@ +// finds all readers and writers and register them +using System.Collections.Generic; +using System.Linq; +using Mono.CecilX; +using Mono.CecilX.Cil; +using Mono.CecilX.Rocks; +using UnityEngine; + +namespace Mirror.Weaver +{ + public static class ReaderWriterProcessor + { + public static bool Process(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed) + { + // find NetworkReader/Writer extensions from Mirror.dll first. + // and NetworkMessage custom writer/reader extensions. + // NOTE: do not include this result in our 'modified' return value, + // otherwise Unity crashes when running tests + ProcessMirrorAssemblyClasses(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed); + + // process dependencies first, this way weaver can process types of other assemblies properly. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2503 + // + // find NetworkReader/Writer extensions in referenced assemblies + IEnumerable assemblyReferences = FindProcessTargetAssemblies(CurrentAssembly, resolver) + .Where(assembly => assembly != null && assembly != CurrentAssembly); + + foreach (AssemblyDefinition referencedAssembly in assemblyReferences) + ProcessAssemblyClasses(CurrentAssembly, referencedAssembly, writers, readers, ref WeavingFailed); + + return ProcessAssemblyClasses(CurrentAssembly, CurrentAssembly, writers, readers, ref WeavingFailed); + } + + // look for assembly instead of relying on CurrentAssembly.MainModule. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3816 + static List FindProcessTargetAssemblies(AssemblyDefinition assembly, IAssemblyResolver resolver) + { + HashSet processedAssemblies = new HashSet(); + List assemblies = new List(); + ProcessAssembly(assembly); + return assemblies; + + void ProcessAssembly(AssemblyDefinition current) + { + // If the assembly has already been processed, we skip it + if (current.FullName == Weaver.MirrorAssemblyName || !processedAssemblies.Add(current.FullName)) + return; + + IEnumerable references = current.MainModule.AssemblyReferences; + + // If there is no Mirror reference, there will be no ReaderWriter or NetworkMessage, so skip + if (references.All(reference => reference.Name != Weaver.MirrorAssemblyName)) + return; + + // Add the assembly to the processed set and list + assemblies.Add(current); + + // Process the references of the current assembly + foreach (AssemblyNameReference reference in references) + { + AssemblyDefinition referencedAssembly = resolver.Resolve(reference); + if (referencedAssembly != null) + ProcessAssembly(referencedAssembly); + } + } + } + + static void ProcessMirrorAssemblyClasses(AssemblyDefinition CurrentAssembly, IAssemblyResolver resolver, Logger Log, Writers writers, Readers readers, ref bool WeavingFailed) + { + // find Mirror.dll in assembly's references. + // those are guaranteed to be resolvable and correct. + // after all, it references them :) + AssemblyNameReference mirrorAssemblyReference = CurrentAssembly.MainModule.FindReference(Weaver.MirrorAssemblyName); + if (mirrorAssemblyReference != null) + { + // resolve the assembly to load the AssemblyDefinition. + // we need to search all types in it. + // if we only were to resolve one known type like in WeaverTypes, + // then we wouldn't need it. + AssemblyDefinition mirrorAssembly = resolver.Resolve(mirrorAssemblyReference); + if (mirrorAssembly != null) + { + ProcessAssemblyClasses(CurrentAssembly, mirrorAssembly, writers, readers, ref WeavingFailed); + } + else Log.Error($"Failed to resolve {mirrorAssemblyReference}"); + } + else Log.Error("Failed to find Mirror AssemblyNameReference. Can't register Mirror.dll readers/writers."); + } + + static bool ProcessAssemblyClasses(AssemblyDefinition CurrentAssembly, AssemblyDefinition assembly, Writers writers, Readers readers, ref bool WeavingFailed) + { + bool modified = false; + foreach (TypeDefinition klass in assembly.MainModule.Types) + { + // extension methods only live in static classes + // static classes are represented as sealed and abstract + if (klass.IsAbstract && klass.IsSealed) + { + // if assembly has any declared writers then it is "modified" + modified |= LoadDeclaredWriters(CurrentAssembly, klass, writers); + modified |= LoadDeclaredReaders(CurrentAssembly, klass, readers); + } + } + + foreach (TypeDefinition klass in assembly.MainModule.Types) + { + // if assembly has any network message then it is modified + modified |= LoadMessageReadWriter(CurrentAssembly.MainModule, writers, readers, klass, ref WeavingFailed); + } + return modified; + } + + static bool LoadMessageReadWriter(ModuleDefinition module, Writers writers, Readers readers, TypeDefinition klass, ref bool WeavingFailed) + { + bool modified = false; + if (!klass.IsAbstract && !klass.IsInterface && klass.ImplementsInterface()) + { + readers.GetReadFunc(module.ImportReference(klass), ref WeavingFailed); + writers.GetWriteFunc(module.ImportReference(klass), ref WeavingFailed); + modified = true; + } + + foreach (TypeDefinition td in klass.NestedTypes) + { + modified |= LoadMessageReadWriter(module, writers, readers, td, ref WeavingFailed); + } + return modified; + } + + static bool LoadDeclaredWriters(AssemblyDefinition currentAssembly, TypeDefinition klass, Writers writers) + { + // register all the writers in this class. Skip the ones with wrong signature + bool modified = false; + foreach (MethodDefinition method in klass.Methods) + { + if (method.Parameters.Count != 2) + continue; + + if (!method.Parameters[0].ParameterType.Is()) + continue; + + if (!method.ReturnType.Is(typeof(void))) + continue; + + if (!method.HasCustomAttribute()) + continue; + + if (method.HasGenericParameters) + continue; + + TypeReference dataType = method.Parameters[1].ParameterType; + writers.Register(dataType, currentAssembly.MainModule.ImportReference(method)); + modified = true; + } + return modified; + } + + static bool LoadDeclaredReaders(AssemblyDefinition currentAssembly, TypeDefinition klass, Readers readers) + { + // register all the reader in this class. Skip the ones with wrong signature + bool modified = false; + foreach (MethodDefinition method in klass.Methods) + { + if (method.Parameters.Count != 1) + continue; + + if (!method.Parameters[0].ParameterType.Is()) + continue; + + if (method.ReturnType.Is(typeof(void))) + continue; + + if (!method.HasCustomAttribute()) + continue; + + if (method.HasGenericParameters) + continue; + + readers.Register(method.ReturnType, currentAssembly.MainModule.ImportReference(method)); + modified = true; + } + return modified; + } + + // helper function to add [RuntimeInitializeOnLoad] attribute to method + static void AddRuntimeInitializeOnLoadAttribute(AssemblyDefinition assembly, WeaverTypes weaverTypes, MethodDefinition method) + { + // NOTE: previously we used reflection because according paul, + // 'weaving Mirror.dll caused unity to rebuild all dlls but in wrong + // order, which breaks rewired' + // it's not obvious why importing an attribute via reflection instead + // of cecil would break anything. let's use cecil. + + // to add a CustomAttribute, we need the attribute's constructor. + // in this case, there are two: empty, and RuntimeInitializeOnLoadType. + // we want the last one, with the type parameter. + MethodDefinition ctor = weaverTypes.runtimeInitializeOnLoadMethodAttribute.GetConstructors().Last(); + //MethodDefinition ctor = weaverTypes.runtimeInitializeOnLoadMethodAttribute.GetConstructors().First(); + // using ctor directly throws: ArgumentException: Member 'System.Void UnityEditor.InitializeOnLoadMethodAttribute::.ctor()' is declared in another module and needs to be imported + // we need to import it first. + CustomAttribute attribute = new CustomAttribute(assembly.MainModule.ImportReference(ctor)); + // add the RuntimeInitializeLoadType.BeforeSceneLoad argument to ctor + attribute.ConstructorArguments.Add(new CustomAttributeArgument(weaverTypes.Import(), RuntimeInitializeLoadType.BeforeSceneLoad)); + method.CustomAttributes.Add(attribute); + } + + // helper function to add [InitializeOnLoad] attribute to method + // (only works in Editor assemblies. check IsEditorAssembly first.) + static void AddInitializeOnLoadAttribute(AssemblyDefinition assembly, WeaverTypes weaverTypes, MethodDefinition method) + { + // NOTE: previously we used reflection because according paul, + // 'weaving Mirror.dll caused unity to rebuild all dlls but in wrong + // order, which breaks rewired' + // it's not obvious why importing an attribute via reflection instead + // of cecil would break anything. let's use cecil. + + // to add a CustomAttribute, we need the attribute's constructor. + // in this case, there's only one - and it's an empty constructor. + MethodDefinition ctor = weaverTypes.initializeOnLoadMethodAttribute.GetConstructors().First(); + // using ctor directly throws: ArgumentException: Member 'System.Void UnityEditor.InitializeOnLoadMethodAttribute::.ctor()' is declared in another module and needs to be imported + // we need to import it first. + CustomAttribute attribute = new CustomAttribute(assembly.MainModule.ImportReference(ctor)); + method.CustomAttributes.Add(attribute); + } + + // adds Mirror.GeneratedNetworkCode.InitReadWriters() method that + // registers all generated writers into Mirror.Writer static class. + // -> uses [RuntimeInitializeOnLoad] attribute so it's invoke at runtime + // -> uses [InitializeOnLoad] if UnityEditor is referenced so it works + // in Editor and in tests too + // + // use ILSpy to see the result (it's in the DLL's 'Mirror' namespace) + public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly, WeaverTypes weaverTypes, Writers writers, Readers readers, TypeDefinition GeneratedCodeClass) + { + MethodDefinition initReadWriters = new MethodDefinition("InitReadWriters", MethodAttributes.Public | + MethodAttributes.Static, + weaverTypes.Import(typeof(void))); + + // add [RuntimeInitializeOnLoad] in any case + AddRuntimeInitializeOnLoadAttribute(currentAssembly, weaverTypes, initReadWriters); + + // add [InitializeOnLoad] if UnityEditor is referenced + if (Helpers.IsEditorAssembly(currentAssembly)) + { + AddInitializeOnLoadAttribute(currentAssembly, weaverTypes, initReadWriters); + } + + // fill function body with reader/writer initializers + ILProcessor worker = initReadWriters.Body.GetILProcessor(); + // for debugging: add a log to see if initialized on load + //worker.Emit(OpCodes.Ldstr, $"[InitReadWriters] called!"); + //worker.Emit(OpCodes.Call, Weaver.weaverTypes.logWarningReference); + writers.InitializeWriters(worker); + readers.InitializeReaders(worker); + worker.Emit(OpCodes.Ret); + + GeneratedCodeClass.Methods.Add(initReadWriters); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta new file mode 100644 index 0000000..cd06284 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f3263602f0a374ecd8d08588b1fc2f76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/ReaderWriterProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs new file mode 100644 index 0000000..ca2d7b9 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs @@ -0,0 +1,104 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [Rpc] methods in NetworkBehaviour + public static class RpcProcessor + { + public static MethodDefinition ProcessRpcInvoke(WeaverTypes weaverTypes, Writers writers, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) + { + string rpcName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, md); + + MethodDefinition rpc = new MethodDefinition(rpcName, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = rpc.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "RPC"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.ClientRpc, ref WeavingFailed)) + return null; + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, rpcCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters); + td.Methods.Add(rpc); + return rpc; + } + + /* + * generates code like: + + public void RpcTest (int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32((uint)param); + base.SendRPCInternal(typeof(class),"RpcTest", writer, 0); + } + public void CallRpcTest (int param) + { + // whatever the user did before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to RpcTest with CallRpcTest + + This method moves all the user's code into the "CallRpc" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + */ + public static MethodDefinition ProcessRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute clientRpcAttr, ref bool WeavingFailed) + { + MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + // add a log message if needed for debugging + //worker.Emit(OpCodes.Ldstr, $"Call ClientRpc function {md.Name}"); + //worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference); + + NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the Rpc call + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed)) + return null; + + int channel = clientRpcAttr.GetField("channel", 0); + bool includeOwner = clientRpcAttr.GetField("includeOwner", true); + + // invoke SendInternal and return + // this + worker.Emit(OpCodes.Ldarg_0); + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, channel); + // includeOwner ? 1 : 0 + worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal); + + NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + + return rpc; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta new file mode 100644 index 0000000..c47fb64 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a3cb7051ff41947e59bba58bdd2b73fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/RpcProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs new file mode 100644 index 0000000..a0b7739 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs @@ -0,0 +1,163 @@ +// Injects server/client active checks for [Server/Client] attributes +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + static class ServerClientAttributeProcessor + { + public static bool Process(WeaverTypes weaverTypes, Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + bool modified = false; + foreach (MethodDefinition md in td.Methods) + { + modified |= ProcessSiteMethod(weaverTypes, Log, md, ref WeavingFailed); + } + + foreach (TypeDefinition nested in td.NestedTypes) + { + modified |= Process(weaverTypes, Log, nested, ref WeavingFailed); + } + return modified; + } + + static bool ProcessSiteMethod(WeaverTypes weaverTypes, Logger Log, MethodDefinition md, ref bool WeavingFailed) + { + if (md.Name == ".cctor" || + md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || + md.Name.StartsWith(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix)) + return false; + + if (md.IsAbstract) + { + if (HasServerClientAttribute(md)) + { + Log.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md); + WeavingFailed = true; + } + return false; + } + + if (md.Body != null && md.Body.Instructions != null) + { + return ProcessMethodAttributes(weaverTypes, md); + } + return false; + } + + public static bool HasServerClientAttribute(MethodDefinition md) + { + foreach (CustomAttribute attr in md.CustomAttributes) + { + switch (attr.Constructor.DeclaringType.ToString()) + { + case "Mirror.ServerAttribute": + case "Mirror.ServerCallbackAttribute": + case "Mirror.ClientAttribute": + case "Mirror.ClientCallbackAttribute": + return true; + default: + break; + } + } + return false; + } + + public static bool ProcessMethodAttributes(WeaverTypes weaverTypes, MethodDefinition md) + { + if (md.HasCustomAttribute()) + InjectServerGuard(weaverTypes, md, true); + else if (md.HasCustomAttribute()) + InjectServerGuard(weaverTypes, md, false); + else if (md.HasCustomAttribute()) + InjectClientGuard(weaverTypes, md, true); + else if (md.HasCustomAttribute()) + InjectClientGuard(weaverTypes, md, false); + else + return false; + + return true; + } + + static void InjectServerGuard(WeaverTypes weaverTypes, MethodDefinition md, bool logWarning) + { + ILProcessor worker = md.Body.GetILProcessor(); + Instruction top = md.Body.Instructions[0]; + + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.NetworkServerGetActive)); + worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); + if (logWarning) + { + worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Server] function '{md.FullName}' called when server was not active")); + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.logWarningReference)); + } + InjectGuardParameters(md, worker, top); + InjectGuardReturnValue(md, worker, top); + worker.InsertBefore(top, worker.Create(OpCodes.Ret)); + } + + static void InjectClientGuard(WeaverTypes weaverTypes, MethodDefinition md, bool logWarning) + { + ILProcessor worker = md.Body.GetILProcessor(); + Instruction top = md.Body.Instructions[0]; + + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.NetworkClientGetActive)); + worker.InsertBefore(top, worker.Create(OpCodes.Brtrue, top)); + if (logWarning) + { + worker.InsertBefore(top, worker.Create(OpCodes.Ldstr, $"[Client] function '{md.FullName}' called when client was not active")); + worker.InsertBefore(top, worker.Create(OpCodes.Call, weaverTypes.logWarningReference)); + } + + InjectGuardParameters(md, worker, top); + InjectGuardReturnValue(md, worker, top); + worker.InsertBefore(top, worker.Create(OpCodes.Ret)); + } + + // this is required to early-out from a function with "ref" or "out" parameters + static void InjectGuardParameters(MethodDefinition md, ILProcessor worker, Instruction top) + { + int offset = md.Resolve().IsStatic ? 0 : 1; + for (int index = 0; index < md.Parameters.Count; index++) + { + ParameterDefinition param = md.Parameters[index]; + if (param.IsOut) + { + // this causes IL2CPP build issues with generic out parameters: + // https://github.com/MirrorNetworking/Mirror/issues/3482 + // TypeReference elementType = param.ParameterType.GetElementType(); + // + // instead we need to use ElementType not GetElementType() + // GetElementType() will get the element type of the inner elementType + // which will return wrong type for arrays and generic + // credit: JamesFrowen + ByReferenceType byRefType = (ByReferenceType)param.ParameterType; + TypeReference elementType = byRefType.ElementType; + + md.Body.Variables.Add(new VariableDefinition(elementType)); + md.Body.InitLocals = true; + + worker.InsertBefore(top, worker.Create(OpCodes.Ldarg, index + offset)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); + worker.InsertBefore(top, worker.Create(OpCodes.Initobj, elementType)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); + worker.InsertBefore(top, worker.Create(OpCodes.Stobj, elementType)); + } + } + } + + // this is required to early-out from a function with a return value. + static void InjectGuardReturnValue(MethodDefinition md, ILProcessor worker, Instruction top) + { + if (!md.ReturnType.Is(typeof(void))) + { + md.Body.Variables.Add(new VariableDefinition(md.ReturnType)); + md.Body.InitLocals = true; + + worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, (byte)(md.Body.Variables.Count - 1))); + worker.InsertBefore(top, worker.Create(OpCodes.Initobj, md.ReturnType)); + worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, md.Body.Variables.Count - 1)); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta new file mode 100644 index 0000000..697a431 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 024f251bf693bb345b90b9177892d534 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/ServerClientAttributeProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs new file mode 100644 index 0000000..a174403 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs @@ -0,0 +1,39 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class SyncObjectInitializer + { + // generates code like: + // this.InitSyncObject(m_sizes); + public static void GenerateSyncObjectInitializer(ILProcessor worker, WeaverTypes weaverTypes, FieldDefinition fd) + { + // register syncobject in network behaviour + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, fd); + worker.Emit(OpCodes.Call, weaverTypes.InitSyncObjectReference); + } + + public static bool ImplementsSyncObject(TypeReference typeRef) + { + try + { + // value types cant inherit from SyncObject + if (typeRef.IsValueType) + { + return false; + } + + return typeRef.Resolve().IsDerivedFrom(); + } + catch + { + // sometimes this will fail if we reference a weird library that can't be resolved, so we just swallow that exception and return false + } + + return false; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta new file mode 100644 index 0000000..97e66ae --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d02219b00b3674e59a2151f41e791688 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs new file mode 100644 index 0000000..8143e86 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class SyncObjectProcessor + { + // ulong = 64 bytes + const int SyncObjectsLimit = 64; + + // Finds SyncObjects fields in a type + // Type should be a NetworkBehaviour + public static List FindSyncObjectsFields(Writers writers, Readers readers, Logger Log, TypeDefinition td, ref bool WeavingFailed) + { + List syncObjects = new List(); + + foreach (FieldDefinition fd in td.Fields) + { + if (fd.FieldType.IsGenericParameter || fd.ContainsGenericParameter) + { + // can't call .Resolve on generic ones + continue; + } + + if (fd.FieldType.Resolve().IsDerivedFrom()) + { + if (fd.IsStatic) + { + Log.Error($"{fd.Name} cannot be static", fd); + WeavingFailed = true; + continue; + } + + // SyncObjects always needs to be readonly to guarantee. + // Weaver calls InitSyncObject on them for dirty bits etc. + // Reassigning at runtime would cause undefined behaviour. + // (C# 'readonly' is called 'initonly' in IL code.) + // + // NOTE: instead of forcing readonly, we could also scan all + // instructions for SyncObject assignments. this would + // make unit tests very difficult though. + if (!fd.IsInitOnly) + { + // just a warning for now. + // many people might still use non-readonly SyncObjects. + Log.Warning($"{fd.Name} should have a 'readonly' keyword in front of the variable because {typeof(SyncObject)}s always need to be initialized by the Weaver.", fd); + + // only log, but keep weaving. no need to break projects. + //WeavingFailed = true; + } + + GenerateReadersAndWriters(writers, readers, fd.FieldType, ref WeavingFailed); + + syncObjects.Add(fd); + } + } + + // SyncObjects dirty mask is 64 bit. can't sync more than 64. + if (syncObjects.Count > 64) + { + Log.Error($"{td.Name} has > {SyncObjectsLimit} SyncObjects (SyncLists etc). Consider refactoring your class into multiple components", td); + WeavingFailed = true; + } + + + return syncObjects; + } + + // Generates serialization methods for synclists + static void GenerateReadersAndWriters(Writers writers, Readers readers, TypeReference tr, ref bool WeavingFailed) + { + if (tr is GenericInstanceType genericInstance) + { + foreach (TypeReference argument in genericInstance.GenericArguments) + { + if (!argument.IsGenericParameter) + { + readers.GetReadFunc(argument, ref WeavingFailed); + writers.GetWriteFunc(argument, ref WeavingFailed); + } + } + } + + if (tr != null) + { + GenerateReadersAndWriters(writers, readers, tr.Resolve().BaseType, ref WeavingFailed); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta new file mode 100644 index 0000000..1408ab3 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 78f71efc83cde4917b7d21efa90bcc9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs new file mode 100644 index 0000000..73a9526 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs @@ -0,0 +1,206 @@ +// [SyncVar] int health; +// is replaced with: +// public int Networkhealth { get; set; } properties. +// this class processes all access to 'health' and replaces it with 'Networkhealth' +using System; +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + public static class SyncVarAttributeAccessReplacer + { + // process the module + public static void Process(Logger Log, ModuleDefinition moduleDef, SyncVarAccessLists syncVarAccessLists) + { + DateTime startTime = DateTime.Now; + + // process all classes in this module + foreach (TypeDefinition td in moduleDef.Types) + { + if (td.IsClass) + { + ProcessClass(Log, syncVarAccessLists, td); + } + } + + Console.WriteLine($" ProcessSitesModule {moduleDef.Name} elapsed time:{(DateTime.Now - startTime)}"); + } + + static void ProcessClass(Logger Log, SyncVarAccessLists syncVarAccessLists, TypeDefinition td) + { + //Console.WriteLine($" ProcessClass {td}"); + + // process all methods in this class + foreach (MethodDefinition md in td.Methods) + { + ProcessMethod(Log, syncVarAccessLists, md); + } + + // processes all nested classes in this class recursively + foreach (TypeDefinition nested in td.NestedTypes) + { + ProcessClass(Log, syncVarAccessLists, nested); + } + } + + static void ProcessMethod(Logger Log, SyncVarAccessLists syncVarAccessLists, MethodDefinition md) + { + // process all references to replaced members with properties + //Log.Warning($" ProcessSiteMethod {md}"); + + // skip static constructor, "MirrorProcessed", "InvokeUserCode_" + if (md.Name == ".cctor" || + md.Name == NetworkBehaviourProcessor.ProcessedFunctionName || + md.Name.StartsWith(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix)) + return; + + // skip abstract + if (md.IsAbstract) + { + return; + } + + // go through all instructions of this method + if (md.Body != null && md.Body.Instructions != null) + { + for (int i = 0; i < md.Body.Instructions.Count;) + { + Instruction instr = md.Body.Instructions[i]; + i += ProcessInstruction(Log, syncVarAccessLists, md, instr, i); + } + } + } + + static int ProcessInstruction(Logger Log, SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction instr, int iCount) + { + // stfld (sets value of a field)? + if (instr.OpCode == OpCodes.Stfld) + { + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldst) + { + ProcessSetInstruction(syncVarAccessLists, md, instr, opFieldst); + } + // operand is a FieldReference in another assembly? + // this is not supported just yet. + // compilation error is better than silently failing SyncVar serialization at runtime. + // https://github.com/MirrorNetworking/Mirror/issues/3525 + else if (instr.Operand is FieldReference opFieldstRef) + { + // resolve it from the other assembly + FieldDefinition field = opFieldstRef.Resolve(); + + // [SyncVar]? + if (field.HasCustomAttribute()) + { + // ILPostProcessor would need to Process() the assembly's + // references before processing this one. + // we can not control the order. + // instead, Log an error to suggest adding a SetSyncVar(value) function. + // this is a very easy solution for a very rare edge case. + Log.Error($"'[SyncVar] {opFieldstRef.DeclaringType.Name}.{opFieldstRef.Name}' in '{field.Module.Name}' is modified by '{md.FullName}' in '{md.Module.Name}'. Modifying a [SyncVar] from another assembly is not supported. Please add a: 'public void Set{opFieldstRef.Name}(value) {{ this.{opFieldstRef.Name} = value; }}' method in '{opFieldstRef.DeclaringType.Name}' and call this function from '{md.FullName}' instead."); + } + } + } + + // ldfld (load value of a field)? + if (instr.OpCode == OpCodes.Ldfld) + { + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldld) + { + // this instruction gets the value of a field. cache the field reference. + ProcessGetInstruction(syncVarAccessLists, md, instr, opFieldld); + } + } + + // ldflda (load field address aka reference) + if (instr.OpCode == OpCodes.Ldflda) + { + // operand is a FieldDefinition in the same assembly? + if (instr.Operand is FieldDefinition opFieldlda) + { + // watch out for initobj instruction + // see https://github.com/vis2k/Mirror/issues/696 + return ProcessLoadAddressInstruction(syncVarAccessLists, md, instr, opFieldlda, iCount); + } + } + + // we processed one instruction (instr) + return 1; + } + + // replaces syncvar write access with the NetworkXYZ.set property calls + static void ProcessSetInstruction(SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction i, FieldDefinition opField) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return; + + // does it set a field that we replaced? + if (syncVarAccessLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + //replace with property + //Log.Warning($" replacing {md.Name}:{i}", opField); + i.OpCode = OpCodes.Call; + i.Operand = replacement; + //Log.Warning($" replaced {md.Name}:{i}", opField); + } + } + + // replaces syncvar read access with the NetworkXYZ.get property calls + static void ProcessGetInstruction(SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction i, FieldDefinition opField) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return; + + // does it set a field that we replaced? + if (syncVarAccessLists.replacementGetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + //replace with property + //Log.Warning($" replacing {md.Name}:{i}"); + i.OpCode = OpCodes.Call; + i.Operand = replacement; + //Log.Warning($" replaced {md.Name}:{i}"); + } + } + + static int ProcessLoadAddressInstruction(SyncVarAccessLists syncVarAccessLists, MethodDefinition md, Instruction instr, FieldDefinition opField, int iCount) + { + // don't replace property call sites in constructors + if (md.Name == ".ctor") + return 1; + + // does it set a field that we replaced? + if (syncVarAccessLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) + { + // we have a replacement for this property + // is the next instruction a initobj? + Instruction nextInstr = md.Body.Instructions[iCount + 1]; + + if (nextInstr.OpCode == OpCodes.Initobj) + { + // we need to replace this code with: + // var tmp = new MyStruct(); + // this.set_Networkxxxx(tmp); + ILProcessor worker = md.Body.GetILProcessor(); + VariableDefinition tmpVariable = new VariableDefinition(opField.FieldType); + md.Body.Variables.Add(tmpVariable); + + worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable)); + worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType)); + worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable)); + worker.InsertBefore(instr, worker.Create(OpCodes.Call, replacement)); + + worker.Remove(instr); + worker.Remove(nextInstr); + return 4; + } + } + + return 1; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs.meta new file mode 100644 index 0000000..ce80ec2 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d48f1ab125e9940a995603796bccc59e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeAccessReplacer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs new file mode 100644 index 0000000..76e3ac7 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs @@ -0,0 +1,515 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Mono.CecilX; +using Mono.CecilX.Cil; +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // Processes [SyncVar] attribute fields in NetworkBehaviour + // not static, because ILPostProcessor is multithreaded + public class SyncVarAttributeProcessor + { + // ulong = 64 bytes + const int SyncVarLimit = 64; + + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + SyncVarAccessLists syncVarAccessLists; + Logger Log; + + string HookParameterMessage(string hookName, TypeReference ValueType) => + $"void {hookName}({ValueType} oldValue, {ValueType} newValue)"; + + public SyncVarAttributeProcessor(AssemblyDefinition assembly, WeaverTypes weaverTypes, SyncVarAccessLists syncVarAccessLists, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.syncVarAccessLists = syncVarAccessLists; + this.Log = Log; + } + + // Get hook method if any + public MethodDefinition GetHookMethod(TypeDefinition td, FieldDefinition syncVar, ref bool WeavingFailed) + { + CustomAttribute syncVarAttr = syncVar.GetCustomAttribute(); + + if (syncVarAttr == null) + return null; + + string hookFunctionName = syncVarAttr.GetField("hook", null); + + if (hookFunctionName == null) + return null; + + return FindHookMethod(td, syncVar, hookFunctionName, ref WeavingFailed); + } + + // Create a field definition for a field that will store the Action delegate instance for the syncvar hook method (only instantiate delegate once) + public FieldDefinition CreateNewActionFieldDefinitionFromHookMethod(FieldDefinition syncVarField) + { + TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>)); + GenericInstanceType syncVarHookActionDelegateType = actionRef.MakeGenericInstanceType(syncVarField.FieldType, syncVarField.FieldType); + string syncVarHookDelegateFieldName = $"_Mirror_SyncVarHookDelegate_{syncVarField.Name}"; + return new FieldDefinition(syncVarHookDelegateFieldName, FieldAttributes.Public, syncVarHookActionDelegateType); + } + + // push hook from GetHookMethod() onto the stack as a new Action. + // allows for reuse without handling static/virtual cases every time. + // perf warning: it is recommended to use this method only when generating IL to create a new Action() in order to store it into a field + // avoid using this to emit IL to instantiate a new action instance every single time one is needed for the same method + public void GenerateNewActionFromHookMethod(FieldDefinition syncVar, ILProcessor worker, MethodDefinition hookMethod) + { + // IL_000a: ldarg.0 + // IL_000b: ldftn instance void Mirror.Examples.Tanks.Tank::ExampleHook(int32, int32) + // IL_0011: newobj instance void class [netstandard]System.Action`2::.ctor(object, native int) + + // we support static hooks and instance hooks. + if (hookMethod.IsStatic) + { + // for static hooks, we need to push 'null' first. + // we can't just push nothing. + // stack would get out of balance because we already pushed + // other stuff above. + worker.Emit(OpCodes.Ldnull); + } + else + { + // for instance hooks, we need to push 'this.' first. + worker.Emit(OpCodes.Ldarg_0); + } + + MethodReference hookMethodReference; + // if the network behaviour class is generic, we need to make the method reference generic for correct IL + if (hookMethod.DeclaringType.HasGenericParameters) + { + hookMethodReference = hookMethod.MakeHostInstanceGeneric(hookMethod.Module, hookMethod.DeclaringType.MakeGenericInstanceType(hookMethod.DeclaringType.GenericParameters.ToArray())); + } + else + { + hookMethodReference = hookMethod; + } + + // we support regular and virtual hook functions. + if (hookMethod.IsVirtual) + { + // for virtual / overwritten hooks, we need different IL. + // this is from simply testing Action = VirtualHook; in C#. + worker.Emit(OpCodes.Dup); + worker.Emit(OpCodes.Ldvirtftn, hookMethodReference); + } + else + { + worker.Emit(OpCodes.Ldftn, hookMethodReference); + } + + // call 'new Action()' constructor to convert the function to an action + // we need to make an instance of the generic Action. + TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>)); + GenericInstanceType genericInstance = actionRef.MakeGenericInstanceType(syncVar.FieldType, syncVar.FieldType); + worker.Emit(OpCodes.Newobj, weaverTypes.ActionT_T.MakeHostInstanceGeneric(assembly.MainModule, genericInstance)); + } + + // generates CIL to set an Action instance field to a new Action(hookMethod) + // this.hookDelegate = new Action(HookMethod); + public void GenerateSyncVarHookDelegateInitializer(ILProcessor worker, FieldDefinition syncVar, FieldDefinition hookDelegate, MethodDefinition hookMethod) + { + // push this + worker.Emit(OpCodes.Ldarg_0); + // push new Action(hookMethod) + GenerateNewActionFromHookMethod(syncVar, worker, hookMethod); + // set field + worker.Emit(OpCodes.Stfld, hookDelegate); + } + + MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, string hookFunctionName, ref bool WeavingFailed) + { + List methods = td.GetMethods(hookFunctionName); + + List methodsWith2Param = new List(methods.Where(m => m.Parameters.Count == 2)); + + if (methodsWith2Param.Count == 0) + { + Log.Error($"Could not find hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + + $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", + syncVar); + WeavingFailed = true; + + return null; + } + + foreach (MethodDefinition method in methodsWith2Param) + { + if (MatchesParameters(syncVar, method)) + { + return method; + } + } + + Log.Error($"Wrong type for Parameter in hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " + + $"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}", + syncVar); + WeavingFailed = true; + + return null; + } + + bool MatchesParameters(FieldDefinition syncVar, MethodDefinition method) + { + // matches void onValueChange(T oldValue, T newValue) + return method.Parameters[0].ParameterType.FullName == syncVar.FieldType.FullName && + method.Parameters[1].ParameterType.FullName == syncVar.FieldType.FullName; + } + + public MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string originalName, FieldDefinition netFieldId) + { + //Create the get method + MethodDefinition get = new MethodDefinition( + $"get_Network{originalName}", MethodAttributes.Public | + MethodAttributes.SpecialName | + MethodAttributes.HideBySig, + fd.FieldType); + + ILProcessor worker = get.Body.GetILProcessor(); + + FieldReference fr; + if (fd.DeclaringType.HasGenericParameters) + { + fr = fd.MakeHostInstanceGeneric(); + } + else + { + fr = fd; + } + + FieldReference netIdFieldReference = null; + if (netFieldId != null) + { + if (netFieldId.DeclaringType.HasGenericParameters) + { + netIdFieldReference = netFieldId.MakeHostInstanceGeneric(); + } + else + { + netIdFieldReference = netFieldId; + } + } + + // [SyncVar] GameObject? + if (fd.FieldType.Is()) + { + // return this.GetSyncVarGameObject(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netIdFieldReference); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fr); + worker.Emit(OpCodes.Call, weaverTypes.getSyncVarGameObjectReference); + worker.Emit(OpCodes.Ret); + } + // [SyncVar] NetworkIdentity? + else if (fd.FieldType.Is()) + { + // return this.GetSyncVarNetworkIdentity(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netIdFieldReference); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fr); + worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference); + worker.Emit(OpCodes.Ret); + } + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) + { + // return this.GetSyncVarNetworkBehaviour(ref field, uint netId); + // this. + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, netIdFieldReference); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fr); + MethodReference getFunc = weaverTypes.getSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, getFunc); + worker.Emit(OpCodes.Ret); + } + // [SyncVar] int, string, etc. + else + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, fr); + worker.Emit(OpCodes.Ret); + } + + get.Body.Variables.Add(new VariableDefinition(fd.FieldType)); + get.Body.InitLocals = true; + get.SemanticsAttributes = MethodSemanticsAttributes.Getter; + + return get; + } + + // for [SyncVar] health, weaver generates + // + // NetworkHealth + // { + // get => health; + // set => GeneratedSyncVarSetter(...) + // } + // + // the setter used to be manually IL generated, but we moved it to C# :) + public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, Dictionary syncVarHookDelegates, ref bool WeavingFailed) + { + //Create the set method + MethodDefinition set = new MethodDefinition($"set_Network{originalName}", MethodAttributes.Public | + MethodAttributes.SpecialName | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = set.Body.GetILProcessor(); + FieldReference fr; + if (fd.DeclaringType.HasGenericParameters) + { + fr = fd.MakeHostInstanceGeneric(); + } + else + { + fr = fd; + } + + FieldReference netIdFieldReference = null; + if (netFieldId != null) + { + if (netFieldId.DeclaringType.HasGenericParameters) + { + netIdFieldReference = netFieldId.MakeHostInstanceGeneric(); + } + else + { + netIdFieldReference = netFieldId; + } + } + + // if (!SyncVarEqual(value, ref playerData)) + Instruction endOfMethod = worker.Create(OpCodes.Nop); + + // NOTE: SyncVar...Equal functions are static. + // don't Emit Ldarg_0 aka 'this'. + + // call WeaverSyncVarSetter(T value, ref T field, ulong dirtyBit, Action OnChanged = null) + // IL_0000: ldarg.0 + // IL_0001: ldarg.1 + // IL_0002: ldarg.0 + // IL_0003: ldflda int32 Mirror.Examples.Tanks.Tank::health + // IL_0008: ldc.i4.1 + // IL_0009: conv.i8 + // IL_000a: ldnull + // IL_000b: call instance void [Mirror]Mirror.NetworkBehaviour::GeneratedSyncVarSetter(!!0, !!0&, uint64, class [netstandard]System.Action`2) + // IL_0010: ret + + // 'this.' for the call + worker.Emit(OpCodes.Ldarg_0); + + // first push 'value' + worker.Emit(OpCodes.Ldarg_1); + + // push 'ref T this.field' + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, fr); + + // push the dirty bit for this SyncVar + worker.Emit(OpCodes.Ldc_I8, dirtyBit); + + // hook? then push 'this.HookDelegate' onto stack + MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed); + if (hookMethod != null) + { + // Create the field that will store a single instance of the hook as a delegate (field will be set in constructor) + FieldDefinition hookActionDelegateField = CreateNewActionFieldDefinitionFromHookMethod(fd); + syncVarHookDelegates[fd] = (hookActionDelegateField, hookMethod); + + // push this.hookActionDelegateField + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldfld, hookActionDelegateField); + } + // otherwise push 'null' as hook + else + { + worker.Emit(OpCodes.Ldnull); + } + + // call GeneratedSyncVarSetter. + // special cases for GameObject/NetworkIdentity/NetworkBehaviour + // passing netId too for persistence. + if (fd.FieldType.Is()) + { + // GameObject setter needs one more parameter: netId field ref + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdFieldReference); + worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_GameObject); + } + else if (fd.FieldType.Is()) + { + // NetworkIdentity setter needs one more parameter: netId field ref + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdFieldReference); + worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity); + } + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) + { + // NetworkIdentity setter needs one more parameter: netId field ref + // (actually its a NetworkBehaviourSyncVar type) + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldflda, netIdFieldReference); + // make generic version of GeneratedSyncVarSetter_NetworkBehaviour + MethodReference getFunc = weaverTypes.generatedSyncVarSetter_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, getFunc); + } + else + { + // make generic version of GeneratedSyncVarSetter + MethodReference generic = weaverTypes.generatedSyncVarSetter.MakeGeneric(assembly.MainModule, fd.FieldType); + worker.Emit(OpCodes.Call, generic); + } + + worker.Append(endOfMethod); + + worker.Emit(OpCodes.Ret); + + set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType)); + set.SemanticsAttributes = MethodSemanticsAttributes.Setter; + + return set; + } + + public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary syncVarNetIds, Dictionary syncVarHookDelegates, long dirtyBit, ref bool WeavingFailed) + { + string originalName = fd.Name; + + // GameObject/NetworkIdentity SyncVars have a new field for netId + FieldDefinition netIdField = null; + // NetworkBehaviour has different field type than other NetworkIdentityFields + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + if (fd.FieldType.IsDerivedFrom() || fd.FieldType.Is()) + { + netIdField = new FieldDefinition($"___{fd.Name}NetId", + FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed + weaverTypes.Import()); + netIdField.DeclaringType = td; + + syncVarNetIds[fd] = netIdField; + } + else if (fd.FieldType.IsNetworkIdentityField()) + { + netIdField = new FieldDefinition($"___{fd.Name}NetId", + FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed + weaverTypes.Import()); + netIdField.DeclaringType = td; + + syncVarNetIds[fd] = netIdField; + } + + MethodDefinition get = GenerateSyncVarGetter(fd, originalName, netIdField); + MethodDefinition set = GenerateSyncVarSetter(td, fd, originalName, dirtyBit, netIdField, syncVarHookDelegates, ref WeavingFailed); + + //NOTE: is property even needed? Could just use a setter function? + //create the property + PropertyDefinition propertyDefinition = new PropertyDefinition($"Network{originalName}", PropertyAttributes.None, fd.FieldType) + { + GetMethod = get, + SetMethod = set + }; + + //add the methods and property to the type. + td.Methods.Add(get); + td.Methods.Add(set); + td.Properties.Add(propertyDefinition); + syncVarAccessLists.replacementSetterProperties[fd] = set; + + // replace getter field if GameObject/NetworkIdentity so it uses + // netId instead + // -> only for GameObjects, otherwise an int syncvar's getter would + // end up in recursion. + if (fd.FieldType.IsNetworkIdentityField()) + { + syncVarAccessLists.replacementGetterProperties[fd] = get; + } + } + + public (List syncVars, Dictionary syncVarNetIds, Dictionary syncVarHookDelegates) ProcessSyncVars(TypeDefinition td, ref bool WeavingFailed) + { + List syncVars = new List(); + Dictionary syncVarNetIds = new Dictionary(); + Dictionary syncVarHookDelegates = new Dictionary(); + + // the mapping of dirtybits to sync-vars is implicit in the order of the fields here. this order is recorded in m_replacementProperties. + // start assigning syncvars at the place the base class stopped, if any + int dirtyBitCounter = syncVarAccessLists.GetSyncVarStart(td.BaseType.FullName); + + // find syncvars + foreach (FieldDefinition fd in td.Fields) + { + if (fd.HasCustomAttribute()) + { + if ((fd.Attributes & FieldAttributes.Static) != 0) + { + Log.Error($"{fd.Name} cannot be static", fd); + WeavingFailed = true; + continue; + } + + if (fd.FieldType.IsGenericParameter) + { + Log.Error($"{fd.Name} has generic type. Generic SyncVars are not supported", fd); + WeavingFailed = true; + continue; + } + + if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType)) + { + Log.Warning($"{fd.Name} has [SyncVar] attribute. SyncLists should not be marked with SyncVar", fd); + } + else + { + syncVars.Add(fd); + + ProcessSyncVar(td, fd, syncVarNetIds, syncVarHookDelegates, 1L << dirtyBitCounter, ref WeavingFailed); + dirtyBitCounter += 1; + + if (dirtyBitCounter > SyncVarLimit) + { + Log.Error($"{td.Name} has > {SyncVarLimit} SyncVars. Consider refactoring your class into multiple components", td); + WeavingFailed = true; + continue; + } + } + } + } + + // add all the new SyncVar __netId fields + foreach (FieldDefinition fd in syncVarNetIds.Values) + { + td.Fields.Add(fd); + } + + // add all of the new SyncVar Action fields + foreach((FieldDefinition hookDelegateInstanceField, MethodDefinition) entry in syncVarHookDelegates.Values) + { + td.Fields.Add(entry.hookDelegateInstanceField); + } + + // include parent class syncvars + // fixes: https://github.com/MirrorNetworking/Mirror/issues/3457 + int parentSyncVarCount = syncVarAccessLists.GetSyncVarStart(td.BaseType.FullName); + syncVarAccessLists.SetNumSyncVars(td.FullName, parentSyncVarCount + syncVars.Count); + + return (syncVars, syncVarNetIds, syncVarHookDelegates); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs.meta new file mode 100644 index 0000000..3b77329 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f52c39bddd95d42b88f9cd554dfd9198 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/SyncVarAttributeProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs new file mode 100644 index 0000000..8d56040 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs @@ -0,0 +1,159 @@ +using Mono.CecilX; +using Mono.CecilX.Cil; + +namespace Mirror.Weaver +{ + // Processes [TargetRpc] methods in NetworkBehaviour + public static class TargetRpcProcessor + { + // helper functions to check if the method has a NetworkConnection parameter + public static bool HasNetworkConnectionParameter(MethodDefinition md) + { + if (md.Parameters.Count > 0) + { + // we need to allow both NetworkConnection, and inheriting types. + // NetworkBehaviour.SendTargetRpc takes a NetworkConnection parameter. + // fixes https://github.com/vis2k/Mirror/issues/3290 + TypeReference type = md.Parameters[0].ParameterType; + return type.Is() || + type.IsDerivedFrom(); + } + return false; + } + + public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed) + { + string trgName = Weaver.GenerateMethodName(RemoteCalls.RemoteProcedureCalls.InvokeRpcPrefix, md); + + MethodDefinition rpc = new MethodDefinition(trgName, MethodAttributes.Family | + MethodAttributes.Static | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + ILProcessor worker = rpc.Body.GetILProcessor(); + Instruction label = worker.Create(OpCodes.Nop); + + NetworkBehaviourProcessor.WriteClientActiveCheck(worker, weaverTypes, md.Name, label, "TargetRPC"); + + // setup for reader + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Castclass, td); + + // NetworkConnection parameter is optional + if (HasNetworkConnectionParameter(md)) + { + // TargetRpcs are sent from server to client. + // on server, we currently support two types: + // TargetRpc(NetworkConnection) + // TargetRpc(NetworkConnectionToClient) + // however, it's always a connection to client. + // in the future, only NetworkConnectionToClient will be supported. + // explicit typing helps catch issues at compile time. + // + // on client, InvokeTargetRpc calls the original code. + // we need to fill in the NetworkConnection parameter. + // NetworkClient.connection is always a connection to server. + // + // we used to pass NetworkClient.connection as the TargetRpc parameter. + // which caused: https://github.com/MirrorNetworking/Mirror/issues/3455 + // when the parameter is defined as a NetworkConnectionToClient. + // + // a client's connection never fits into a NetworkConnectionToClient. + // we need to always pass null here. + worker.Emit(OpCodes.Ldnull); + } + + // process reader parameters and skip first one if first one is NetworkConnection + if (!NetworkBehaviourProcessor.ReadArguments(md, readers, Log, worker, RemoteCallType.TargetRpc, ref WeavingFailed)) + return null; + + // invoke actual command function + worker.Emit(OpCodes.Callvirt, rpcCallFunc); + worker.Emit(OpCodes.Ret); + + NetworkBehaviourProcessor.AddInvokeParameters(weaverTypes, rpc.Parameters); + td.Methods.Add(rpc); + return rpc; + } + + /* generates code like: + public void TargetTest (NetworkConnection conn, int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32 ((uint)param); + base.SendTargetRPCInternal (conn, typeof(class), "TargetTest", val); + } + public void CallTargetTest (NetworkConnection conn, int param) + { + // whatever the user did before + } + + or if optional: + public void TargetTest (int param) + { + NetworkWriter writer = new NetworkWriter (); + writer.WritePackedUInt32 ((uint)param); + base.SendTargetRPCInternal (null, typeof(class), "TargetTest", val); + } + public void CallTargetTest (int param) + { + // whatever the user did before + } + + Originally HLAPI put the send message code inside the Call function + and then proceeded to replace every call to TargetTest with CallTargetTest + + This method moves all the user's code into the "CallTargetRpc" method + and replaces the body of the original method with the send message code. + This way we do not need to modify the code anywhere else, and this works + correctly in dependent assemblies + + */ + public static MethodDefinition ProcessTargetRpcCall(WeaverTypes weaverTypes, Writers writers, Logger Log, TypeDefinition td, MethodDefinition md, CustomAttribute targetRpcAttr, ref bool WeavingFailed) + { + MethodDefinition rpc = MethodProcessor.SubstituteMethod(Log, td, md, ref WeavingFailed); + + ILProcessor worker = md.Body.GetILProcessor(); + + NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes); + + NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes); + + // write all the arguments that the user passed to the TargetRpc call + // (skip first one if first one is NetworkConnection) + if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.TargetRpc, ref WeavingFailed)) + return null; + + // invoke SendInternal and return + // this + worker.Emit(OpCodes.Ldarg_0); + if (HasNetworkConnectionParameter(md)) + { + // connection + worker.Emit(OpCodes.Ldarg_1); + } + else + { + // null + worker.Emit(OpCodes.Ldnull); + } + // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions + worker.Emit(OpCodes.Ldstr, md.FullName); + // pass the function hash so we don't have to compute it at runtime + // otherwise each GetStableHash call requires O(N) complexity. + // noticeable for long function names: + // https://github.com/MirrorNetworking/Mirror/issues/3375 + worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode()); + // writer + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0)); + worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal); + + NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes); + + worker.Emit(OpCodes.Ret); + + return rpc; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta new file mode 100644 index 0000000..f4019ff --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: fb3ce6c6f3f2942ae88178b86f5a8282 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Processors/TargetRpcProcessor.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs b/Assets/Mirror/Editor/Weaver/Readers.cs new file mode 100644 index 0000000..875f8b7 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Readers.cs @@ -0,0 +1,404 @@ +using System; +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; +// to use Mono.CecilX.Rocks here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.Rocks. +// otherwise we get an unknown import exception. +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class Readers + { + // Readers are only for this assembly. + // can't be used from another assembly, otherwise we will get: + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + TypeDefinition GeneratedCodeClass; + Logger Log; + + Dictionary readFuncs = + new Dictionary(new TypeReferenceComparer()); + + public Readers(AssemblyDefinition assembly, WeaverTypes weaverTypes, TypeDefinition GeneratedCodeClass, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.GeneratedCodeClass = GeneratedCodeClass; + this.Log = Log; + } + + internal void Register(TypeReference dataType, MethodReference methodReference) + { + // sometimes we define multiple read methods for the same type. + // for example: + // ReadInt() // alwasy writes 4 bytes: should be available to the user for binary protocols etc. + // ReadVarInt() // varint compression: we may want Weaver to always use this for minimal bandwidth + // give the user a way to define the weaver prefered one if two exists: + // "[WeaverPriority]" attribute is automatically detected and prefered. + MethodDefinition methodDefinition = methodReference.Resolve(); + bool priority = methodDefinition.HasCustomAttribute(); + // if (priority) Log.Warning($"Weaver: Registering priority Read<{dataType.FullName}> with {methodReference.FullName}.", methodReference); + + // Weaver sometimes calls Register for multiple times because we resolve assemblies multiple times. + // if the function name is the same: always use the latest one. + // if the function name differes: use the priority one. + if (readFuncs.TryGetValue(dataType, out MethodReference existingMethod) && // if it was already defined + existingMethod.FullName != methodReference.FullName && // and this one is a different name + !priority) // and it's not the priority one + { + return; // then skip + } + + // we need to import type when we Initialize Readers so import here in case it is used anywhere else + TypeReference imported = assembly.MainModule.ImportReference(dataType); + readFuncs[imported] = methodReference; + } + + void RegisterReadFunc(TypeReference typeReference, MethodDefinition newReaderFunc) + { + Register(typeReference, newReaderFunc); + GeneratedCodeClass.Methods.Add(newReaderFunc); + } + + // Finds existing reader for type, if non exists trys to create one + public MethodReference GetReadFunc(TypeReference variable, ref bool WeavingFailed) + { + if (readFuncs.TryGetValue(variable, out MethodReference foundFunc)) + return foundFunc; + + TypeReference importedVariable = assembly.MainModule.ImportReference(variable); + return GenerateReader(importedVariable, ref WeavingFailed); + } + + MethodReference GenerateReader(TypeReference variableReference, ref bool WeavingFailed) + { + // Arrays are special, if we resolve them, we get the element type, + // so the following ifs might choke on it for scriptable objects + // or other objects that require a custom serializer + // thus check if it is an array and skip all the checks. + if (variableReference.IsArray) + { + if (variableReference.IsMultidimensionalArray()) + { + Log.Error($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); + WeavingFailed = true; + return null; + } + + return GenerateReadCollection(variableReference, variableReference.GetElementType(), nameof(NetworkReaderExtensions.ReadArray), ref WeavingFailed); + } + + TypeDefinition variableDefinition = variableReference.Resolve(); + + // check if the type is completely invalid + if (variableDefinition == null) + { + Log.Error($"{variableReference.Name} is not a supported type", variableReference); + WeavingFailed = true; + return null; + } + else if (variableReference.IsByReference) + { + // error?? + Log.Error($"Cannot pass type {variableReference.Name} by reference", variableReference); + WeavingFailed = true; + return null; + } + + // use existing func for known types + if (variableDefinition.IsEnum) + { + return GenerateEnumReadFunc(variableReference, ref WeavingFailed); + } + else if (variableDefinition.Is(typeof(ArraySegment<>))) + { + return GenerateArraySegmentReadFunc(variableReference, ref WeavingFailed); + } + else if (variableDefinition.Is(typeof(List<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList), ref WeavingFailed); + } + else if (variableDefinition.Is(typeof(HashSet<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadHashSet), ref WeavingFailed); + } + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + else if (variableReference.IsDerivedFrom() || variableReference.Is()) + { + return GetNetworkBehaviourReader(variableReference); + } + + // check if reader generation is applicable on this type + if (variableDefinition.IsDerivedFrom()) + { + Log.Error($"Cannot generate reader for component type {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableReference.Is()) + { + Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableReference.Is()) + { + Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.HasGenericParameters) + { + Log.Error($"Cannot generate reader for generic variable {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.IsInterface) + { + Log.Error($"Cannot generate reader for interface {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + if (variableDefinition.IsAbstract) + { + Log.Error($"Cannot generate reader for abstract class {variableReference.Name}. Use a supported type or provide a custom reader", variableReference); + WeavingFailed = true; + return null; + } + + return GenerateClassOrStructReadFunction(variableReference, ref WeavingFailed); + } + + MethodReference GetNetworkBehaviourReader(TypeReference variableReference) + { + // uses generic ReadNetworkBehaviour rather than having weaver create one for each NB + MethodReference generic = weaverTypes.readNetworkBehaviourGeneric; + + MethodReference readFunc = generic.MakeGeneric(assembly.MainModule, variableReference); + + // register function so it is added to Reader + // use Register instead of RegisterWriteFunc because this is not a generated function + Register(variableReference, readFunc); + + return readFunc; + } + + MethodDefinition GenerateEnumReadFunc(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + worker.Emit(OpCodes.Ldarg_0); + + TypeReference underlyingType = variable.Resolve().GetEnumUnderlyingType(); + MethodReference underlyingFunc = GetReadFunc(underlyingType, ref WeavingFailed); + + worker.Emit(OpCodes.Call, underlyingFunc); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, ref bool WeavingFailed) + { + GenericInstanceType genericInstance = (GenericInstanceType)variable; + TypeReference elementType = genericInstance.GenericArguments[0]; + + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + // $array = reader.Read<[T]>() + ArrayType arrayType = elementType.MakeArrayType(); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, GetReadFunc(arrayType, ref WeavingFailed)); + + // return new ArraySegment($array); + worker.Emit(OpCodes.Newobj, weaverTypes.ArraySegmentConstructorReference.MakeHostInstanceGeneric(assembly.MainModule, genericInstance)); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + MethodDefinition GenerateReaderFunction(TypeReference variable) + { + string functionName = $"_Read_{variable.FullName}"; + + // create new reader for this type + MethodDefinition readerFunc = new MethodDefinition(functionName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig, + variable); + + readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, weaverTypes.Import())); + readerFunc.Body.InitLocals = true; + RegisterReadFunc(variable, readerFunc); + + return readerFunc; + } + + MethodDefinition GenerateReadCollection(TypeReference variable, TypeReference elementType, string readerFunction, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + // generate readers for the element + GetReadFunc(elementType, ref WeavingFailed); + + ModuleDefinition module = assembly.MainModule; + TypeReference readerExtensions = module.ImportReference(typeof(NetworkReaderExtensions)); + MethodReference listReader = Resolvers.ResolveMethod(readerExtensions, assembly, Log, readerFunction, ref WeavingFailed); + + GenericInstanceMethod methodRef = new GenericInstanceMethod(listReader); + methodRef.GenericArguments.Add(elementType); + + // generates + // return reader.ReadList(); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldarg_0); // reader + worker.Emit(OpCodes.Call, methodRef); // Read + + worker.Emit(OpCodes.Ret); + + return readerFunc; + } + + MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition readerFunc = GenerateReaderFunction(variable); + + // create local for return value + readerFunc.Body.Variables.Add(new VariableDefinition(variable)); + + ILProcessor worker = readerFunc.Body.GetILProcessor(); + + TypeDefinition td = variable.Resolve(); + + if (!td.IsValueType) + GenerateNullCheck(worker, ref WeavingFailed); + + CreateNew(variable, worker, td, ref WeavingFailed); + ReadAllFields(variable, worker, ref WeavingFailed); + + worker.Emit(OpCodes.Ldloc_0); + worker.Emit(OpCodes.Ret); + return readerFunc; + } + + void GenerateNullCheck(ILProcessor worker, ref bool WeavingFailed) + { + // if (!reader.ReadBoolean()) { + // return null; + // } + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, GetReadFunc(weaverTypes.Import(), ref WeavingFailed)); + + Instruction labelEmptyArray = worker.Create(OpCodes.Nop); + worker.Emit(OpCodes.Brtrue, labelEmptyArray); + // return null + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ret); + worker.Append(labelEmptyArray); + } + + // Initialize the local variable with a new instance + void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td, ref bool WeavingFailed) + { + if (variable.IsValueType) + { + // structs are created with Initobj + worker.Emit(OpCodes.Ldloca, 0); + worker.Emit(OpCodes.Initobj, variable); + } + else if (td.IsDerivedFrom()) + { + GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(weaverTypes.ScriptableObjectCreateInstanceMethod); + genericInstanceMethod.GenericArguments.Add(variable); + worker.Emit(OpCodes.Call, genericInstanceMethod); + worker.Emit(OpCodes.Stloc_0); + } + else + { + // classes are created with their constructor + MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable); + if (ctor == null) + { + Log.Error($"{variable.Name} can't be deserialized because it has no default constructor. Don't use {variable.Name} in [SyncVar]s, Rpcs, Cmds, etc.", variable); + WeavingFailed = true; + return; + } + + MethodReference ctorRef = assembly.MainModule.ImportReference(ctor); + + worker.Emit(OpCodes.Newobj, ctorRef); + worker.Emit(OpCodes.Stloc_0); + } + } + + void ReadAllFields(TypeReference variable, ILProcessor worker, ref bool WeavingFailed) + { + foreach (FieldDefinition field in variable.FindAllPublicFields()) + { + // mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime + OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc; + worker.Emit(opcode, 0); + MethodReference readFunc = GetReadFunc(field.FieldType, ref WeavingFailed); + if (readFunc != null) + { + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Call, readFunc); + } + else + { + Log.Error($"{field.Name} has an unsupported type", field); + WeavingFailed = true; + } + FieldReference fieldRef = assembly.MainModule.ImportReference(field); + + worker.Emit(OpCodes.Stfld, fieldRef); + } + } + + // Save a delegate for each one of the readers into Reader.read + internal void InitializeReaders(ILProcessor worker) + { + ModuleDefinition module = assembly.MainModule; + + TypeReference genericReaderClassRef = module.ImportReference(typeof(Reader<>)); + + System.Reflection.FieldInfo fieldInfo = typeof(Reader<>).GetField(nameof(Reader.read)); + FieldReference fieldRef = module.ImportReference(fieldInfo); + TypeReference networkReaderRef = module.ImportReference(typeof(NetworkReader)); + TypeReference funcRef = module.ImportReference(typeof(Func<,>)); + MethodReference funcConstructorRef = module.ImportReference(typeof(Func<,>).GetConstructors()[0]); + + foreach (KeyValuePair kvp in readFuncs) + { + TypeReference targetType = kvp.Key; + MethodReference readFunc = kvp.Value; + + // create a Func delegate + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, readFunc); + GenericInstanceType funcGenericInstance = funcRef.MakeGenericInstanceType(networkReaderRef, targetType); + MethodReference funcConstructorInstance = funcConstructorRef.MakeHostInstanceGeneric(assembly.MainModule, funcGenericInstance); + worker.Emit(OpCodes.Newobj, funcConstructorInstance); + + // save it in Reader.read + GenericInstanceType genericInstance = genericReaderClassRef.MakeGenericInstanceType(targetType); + FieldReference specializedField = fieldRef.SpecializeField(assembly.MainModule, genericInstance); + worker.Emit(OpCodes.Stsfld, specializedField); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs.meta b/Assets/Mirror/Editor/Weaver/Readers.cs.meta new file mode 100644 index 0000000..5831615 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Readers.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: be40277098a024539bf63d0205cae824 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Readers.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs b/Assets/Mirror/Editor/Weaver/Resolvers.cs new file mode 100644 index 0000000..0af32ca --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Resolvers.cs @@ -0,0 +1,126 @@ +// all the resolve functions for the weaver +// NOTE: these functions should be made extensions, but right now they still +// make heavy use of Weaver.fail and we'd have to check each one's return +// value for null otherwise. +// (original FieldType.Resolve returns null if not found too, so +// exceptions would be a bit inconsistent here) +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public static class Resolvers + { + public static MethodReference ResolveMethod(TypeReference tr, AssemblyDefinition assembly, Logger Log, string name, ref bool WeavingFailed) + { + if (tr == null) + { + Log.Error($"Cannot resolve method {name} without a class"); + WeavingFailed = true; + return null; + } + MethodReference method = ResolveMethod(tr, assembly, Log, m => m.Name == name, ref WeavingFailed); + if (method == null) + { + Log.Error($"Method not found with name {name} in type {tr.Name}", tr); + WeavingFailed = true; + } + return method; + } + + public static MethodReference ResolveMethod(TypeReference t, AssemblyDefinition assembly, Logger Log, System.Func predicate, ref bool WeavingFailed) + { + foreach (MethodDefinition methodRef in t.Resolve().Methods) + { + if (predicate(methodRef)) + { + return assembly.MainModule.ImportReference(methodRef); + } + } + + Log.Error($"Method not found in type {t.Name}", t); + WeavingFailed = true; + return null; + } + + public static FieldReference ResolveField(TypeReference tr, AssemblyDefinition assembly, Logger Log, string name, ref bool WeavingFailed) + { + if (tr == null) + { + Log.Error($"Cannot resolve Field {name} without a class"); + WeavingFailed = true; + return null; + } + FieldReference field = ResolveField(tr, assembly, Log, m => m.Name == name, ref WeavingFailed); + if (field == null) + { + Log.Error($"Field not found with name {name} in type {tr.Name}", tr); + WeavingFailed = true; + } + return field; + } + + public static FieldReference ResolveField(TypeReference t, AssemblyDefinition assembly, Logger Log, System.Func predicate, ref bool WeavingFailed) + { + foreach (FieldDefinition fieldRef in t.Resolve().Fields) + { + if (predicate(fieldRef)) + { + return assembly.MainModule.ImportReference(fieldRef); + } + } + + Log.Error($"Field not found in type {t.Name}", t); + WeavingFailed = true; + return null; + } + + public static MethodReference TryResolveMethodInParents(TypeReference tr, AssemblyDefinition assembly, string name) + { + if (tr == null) + { + return null; + } + foreach (MethodDefinition methodDef in tr.Resolve().Methods) + { + if (methodDef.Name == name) + { + MethodReference methodRef = methodDef; + if (tr.IsGenericInstance) + { + methodRef = methodRef.MakeHostInstanceGeneric(tr.Module, (GenericInstanceType)tr); + } + return assembly.MainModule.ImportReference(methodRef); + } + } + + // Could not find the method in this class, try the parent + return TryResolveMethodInParents(tr.Resolve().BaseType.ApplyGenericParameters(tr), assembly, name); + } + + public static MethodDefinition ResolveDefaultPublicCtor(TypeReference variable) + { + foreach (MethodDefinition methodRef in variable.Resolve().Methods) + { + if (methodRef.Name == ".ctor" && + methodRef.Resolve().IsPublic && + methodRef.Parameters.Count == 0) + { + return methodRef; + } + } + return null; + } + + public static MethodReference ResolveProperty(TypeReference tr, AssemblyDefinition assembly, string name) + { + foreach (PropertyDefinition pd in tr.Resolve().Properties) + { + if (pd.Name == name) + { + return assembly.MainModule.ImportReference(pd.GetMethod); + } + } + return null; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta b/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta new file mode 100644 index 0000000..49235c1 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Resolvers.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3039a59c76aec43c797ad66930430367 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Resolvers.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs b/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs new file mode 100644 index 0000000..fa7a682 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs @@ -0,0 +1,32 @@ +// tracks SyncVar read/write access when processing NetworkBehaviour, +// to later be replaced by SyncVarAccessReplacer. +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // This data is flushed each time - if we are run multiple times in the same process/domain + public class SyncVarAccessLists + { + // setter functions that replace [SyncVar] member variable references. dict + public Dictionary replacementSetterProperties = + new Dictionary(); + + // getter functions that replace [SyncVar] member variable references. dict + public Dictionary replacementGetterProperties = + new Dictionary(); + + // amount of SyncVars per class. dict + // necessary for SyncVar dirty bits, where inheriting classes start + // their dirty bits at base class SyncVar amount. + public Dictionary numSyncVars = new Dictionary(); + + public int GetSyncVarStart(string className) => + numSyncVars.TryGetValue(className, out int value) ? value : 0; + + public void SetNumSyncVars(string className, int num) + { + numSyncVars[className] = num; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs.meta b/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs.meta new file mode 100644 index 0000000..31a2ed3 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6905230c3c4c4e158760065a93380e83 +timeCreated: 1629348618 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/SyncVarAccessLists.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs new file mode 100644 index 0000000..e3c31d5 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + // Compares TypeReference using FullName + public class TypeReferenceComparer : IEqualityComparer + { + public bool Equals(TypeReference x, TypeReference y) => + x.FullName == y.FullName; + + public int GetHashCode(TypeReference obj) => + obj.FullName.GetHashCode(); + } +} diff --git a/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta new file mode 100644 index 0000000..ec97f9d --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 55eb9eb8794946f4da7ad39788c9920b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/TypeReferenceComparer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef new file mode 100644 index 0000000..987382c --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef @@ -0,0 +1,21 @@ +{ + "name": "Unity.Mirror.CodeGen", + "rootNamespace": "", + "references": [ + "GUID:30817c1a0e6d646d99c048fc403f5979" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": true, + "precompiledReferences": [ + "Mono.CecilX.dll", + "Mono.CecilX.Rocks.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta new file mode 100644 index 0000000..5fc0fe1 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 1d0b9d21c3ff546a4aa32399dfd33474 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Unity.Mirror.CodeGen.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs b/Assets/Mirror/Editor/Weaver/Weaver.cs new file mode 100644 index 0000000..3aef7b8 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Mono.CecilX; +using Mono.CecilX.Cil; +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + internal class Weaver + { + // generated code class + public const string GeneratedCodeNamespace = "Mirror"; + public const string GeneratedCodeClassName = "GeneratedNetworkCode"; + TypeDefinition GeneratedCodeClass; + + // for resolving Mirror.dll in ReaderWriterProcessor, we need to know + // Mirror.dll name + public const string MirrorAssemblyName = "Mirror"; + + WeaverTypes weaverTypes; + SyncVarAccessLists syncVarAccessLists; + AssemblyDefinition CurrentAssembly; + Writers writers; + Readers readers; + + // in case of weaver errors, we don't stop immediately. + // we log all errors and then eventually return false if + // weaving has failed. + // this way the user can fix multiple errors at once, instead of having + // to fix -> recompile -> fix -> recompile for one error at a time. + bool WeavingFailed; + + // logger functions can be set from the outside. + // for example, Debug.Log or ILPostProcessor Diagnostics log for + // multi threaded logging. + public Logger Log; + + // remote actions now support overloads, + // -> but IL2CPP doesnt like it when two generated methods + // -> have the same signature, + // -> so, append the signature to the generated method name, + // -> to create a unique name + // Example: + // RpcTeleport(Vector3 position) -> InvokeUserCode_RpcTeleport__Vector3() + // RpcTeleport(Vector3 position, Quaternion rotation) -> InvokeUserCode_RpcTeleport__Vector3Quaternion() + // fixes https://github.com/vis2k/Mirror/issues/3060 + public static string GenerateMethodName(string initialPrefix, MethodDefinition md) + { + initialPrefix += md.Name; + + for (int i = 0; i < md.Parameters.Count; ++i) + { + // with __ so it's more obvious that this is the parameter suffix. + // otherwise RpcTest(int) => RpcTestInt(int) which is not obvious. + initialPrefix += $"__{md.Parameters[i].ParameterType.Name}"; + } + + return initialPrefix; + } + + public Weaver(Logger Log) + { + this.Log = Log; + } + + // returns 'true' if modified (=if we did anything) + bool WeaveNetworkBehavior(TypeDefinition td) + { + if (!td.IsClass) + return false; + + if (!td.IsDerivedFrom()) + { + if (td.IsDerivedFrom()) + MonoBehaviourProcessor.Process(Log, td, ref WeavingFailed); + return false; + } + + // process this and base classes from parent to child order + + List behaviourClasses = new List(); + + TypeDefinition parent = td; + while (parent != null) + { + if (parent.Is()) + { + break; + } + + try + { + behaviourClasses.Insert(0, parent); + parent = parent.BaseType.Resolve(); + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + //Console.WriteLine("AssemblyResolutionException: "+ ex.ToString()); + break; + } + } + + bool modified = false; + foreach (TypeDefinition behaviour in behaviourClasses) + { + modified |= new NetworkBehaviourProcessor(CurrentAssembly, weaverTypes, syncVarAccessLists, writers, readers, Log, behaviour).Process(ref WeavingFailed); + } + return modified; + } + + bool WeaveModule(ModuleDefinition moduleDefinition) + { + bool modified = false; + + Stopwatch watch = Stopwatch.StartNew(); + watch.Start(); + + // ModuleDefinition.Types only finds top level types. + // GetAllTypes recursively finds all nested types as well. + // fixes nested types not being weaved, for example: + // class Parent { // ModuleDefinition.Types finds this + // class Child { // .Types.NestedTypes finds this + // class GrandChild {} // only GetAllTypes finds this too + // } + // } + // note this is not about inheritance, only about type definitions. + // see test: NetworkBehaviourTests.DeeplyNested() + foreach (TypeDefinition td in moduleDefinition.GetAllTypes()) + { + if (td.IsClass && td.BaseType.CanBeResolved()) + { + modified |= WeaveNetworkBehavior(td); + modified |= ServerClientAttributeProcessor.Process(weaverTypes, Log, td, ref WeavingFailed); + } + } + + watch.Stop(); + Console.WriteLine($"Weave behaviours and messages took {watch.ElapsedMilliseconds} milliseconds"); + + return modified; + } + + void CreateGeneratedCodeClass() + { + // create "Mirror.GeneratedNetworkCode" class which holds all + // Readers and Writers + GeneratedCodeClass = new TypeDefinition(GeneratedCodeNamespace, GeneratedCodeClassName, + TypeAttributes.BeforeFieldInit | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Abstract | TypeAttributes.Sealed, + weaverTypes.Import()); + } + + void ToggleWeaverFuse() + { + // // find Weaved() function + MethodDefinition func = weaverTypes.weaverFuseMethod.Resolve(); + // // change return 0 to return 1 + + ILProcessor worker = func.Body.GetILProcessor(); + func.Body.Instructions[0] = worker.Create(OpCodes.Ldc_I4_1); + } + + // Weave takes an AssemblyDefinition to be compatible with both old and + // new weavers: + // * old takes a filepath, new takes a in-memory byte[] + // * old uses DefaultAssemblyResolver with added dependencies paths, + // new uses ...? + // + // => assembly: the one we are currently weaving (MyGame.dll) + // => resolver: useful in case we need to resolve any of the assembly's + // assembly.MainModule.AssemblyReferences. + // -> we can resolve ANY of them given that the resolver + // works properly (need custom one for ILPostProcessor) + // -> IMPORTANT: .Resolve() takes an AssemblyNameReference. + // those from assembly.MainModule.AssemblyReferences are + // guaranteed to be resolve-able. + // Parsing from a string for Library/.../Mirror.dll + // would not be guaranteed to be resolve-able because + // for ILPostProcessor we can't assume where Mirror.dll + // is etc. + public bool Weave(AssemblyDefinition assembly, IAssemblyResolver resolver, out bool modified) + { + WeavingFailed = false; + modified = false; + try + { + CurrentAssembly = assembly; + + // fix "No writer found for ..." error + // https://github.com/vis2k/Mirror/issues/2579 + // -> when restarting Unity, weaver would try to weave a DLL + // again + // -> resulting in two GeneratedNetworkCode classes (see ILSpy) + // -> the second one wouldn't have all the writer types setup + if (CurrentAssembly.MainModule.ContainsClass(GeneratedCodeNamespace, GeneratedCodeClassName)) + { + //Log.Warning($"Weaver: skipping {CurrentAssembly.Name} because already weaved"); + return true; + } + + weaverTypes = new WeaverTypes(CurrentAssembly, Log, ref WeavingFailed); + + // weaverTypes are needed for CreateGeneratedCodeClass + CreateGeneratedCodeClass(); + + // WeaverList depends on WeaverTypes setup because it uses Import + syncVarAccessLists = new SyncVarAccessLists(); + + // initialize readers & writers with this assembly. + // we need to do this in every Process() call. + // otherwise we would get + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + // errors when still using the previous module's reader/writer funcs. + writers = new Writers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log); + readers = new Readers(CurrentAssembly, weaverTypes, GeneratedCodeClass, Log); + + Stopwatch rwstopwatch = Stopwatch.StartNew(); + // Need to track modified from ReaderWriterProcessor too because it could find custom read/write functions or create functions for NetworkMessages + modified = ReaderWriterProcessor.Process(CurrentAssembly, resolver, Log, writers, readers, ref WeavingFailed); + rwstopwatch.Stop(); + Console.WriteLine($"Find all reader and writers took {rwstopwatch.ElapsedMilliseconds} milliseconds"); + + ModuleDefinition moduleDefinition = CurrentAssembly.MainModule; + Console.WriteLine($"Script Module: {moduleDefinition.Name}"); + + modified |= WeaveModule(moduleDefinition); + + if (WeavingFailed) + { + return false; + } + + if (modified) + { + SyncVarAttributeAccessReplacer.Process(Log, moduleDefinition, syncVarAccessLists); + + // add class that holds read/write functions + moduleDefinition.Types.Add(GeneratedCodeClass); + + ReaderWriterProcessor.InitializeReaderAndWriters(CurrentAssembly, weaverTypes, writers, readers, GeneratedCodeClass); + + // DO NOT WRITE here. + // CompilationFinishedHook writes to the file. + // ILPostProcessor writes to in-memory assembly. + // it depends on the caller. + //CurrentAssembly.Write(new WriterParameters{ WriteSymbols = true }); + } + + // if weaving succeeded, switch on the Weaver Fuse in Mirror.dll + if (CurrentAssembly.Name.Name == MirrorAssemblyName) + { + ToggleWeaverFuse(); + } + + return true; + } + catch (Exception e) + { + Log.Error($"Exception :{e}"); + WeavingFailed = true; + return false; + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs.meta b/Assets/Mirror/Editor/Weaver/Weaver.cs.meta new file mode 100644 index 0000000..2eaf569 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: de160f52931054064852f2afd7e7a86f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Weaver.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs new file mode 100644 index 0000000..efedd27 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.Serialization; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + [Serializable] + public abstract class WeaverException : Exception + { + public MemberReference MemberReference { get; } + + protected WeaverException(string message, MemberReference member) : base(message) + { + MemberReference = member; + } + + protected WeaverException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) {} + } + + [Serializable] + public class GenerateWriterException : WeaverException + { + public GenerateWriterException(string message, MemberReference member) : base(message, member) {} + protected GenerateWriterException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) {} + } +} diff --git a/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta new file mode 100644 index 0000000..4ef61d6 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverExceptions.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8aaaf6193bad7424492677f8e81f1b30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/WeaverExceptions.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs new file mode 100644 index 0000000..aa0d42d --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs @@ -0,0 +1,171 @@ +using System; +using Mono.CecilX; +using UnityEditor; +using UnityEngine; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class WeaverTypes + { + public MethodReference ScriptableObjectCreateInstanceMethod; + + public FieldReference NetworkBehaviourDirtyBitsReference; + public MethodReference GetWriterReference; + public MethodReference ReturnWriterReference; + + public MethodReference NetworkClientConnectionReference; + + public MethodReference RemoteCallDelegateConstructor; + + public MethodReference NetworkServerGetActive; + public MethodReference NetworkClientGetActive; + + // custom attribute types + public MethodReference InitSyncObjectReference; + + // array segment + public MethodReference ArraySegmentConstructorReference; + + // Action for SyncVar Hooks + public MethodReference ActionT_T; + + // syncvar + public MethodReference generatedSyncVarSetter; + public MethodReference generatedSyncVarSetter_GameObject; + public MethodReference generatedSyncVarSetter_NetworkIdentity; + public MethodReference generatedSyncVarSetter_NetworkBehaviour_T; + public MethodReference generatedSyncVarDeserialize; + public MethodReference generatedSyncVarDeserialize_GameObject; + public MethodReference generatedSyncVarDeserialize_NetworkIdentity; + public MethodReference generatedSyncVarDeserialize_NetworkBehaviour_T; + public MethodReference getSyncVarGameObjectReference; + public MethodReference getSyncVarNetworkIdentityReference; + public MethodReference getSyncVarNetworkBehaviourReference; + public MethodReference registerCommandReference; + public MethodReference registerRpcReference; + public MethodReference getTypeFromHandleReference; + public MethodReference logErrorReference; + public MethodReference logWarningReference; + public MethodReference sendCommandInternal; + public MethodReference sendRpcInternal; + public MethodReference sendTargetRpcInternal; + + public MethodReference readNetworkBehaviourGeneric; + + public TypeReference weaverFuseType; + public MethodReference weaverFuseMethod; + + // attributes + public TypeDefinition initializeOnLoadMethodAttribute; + public TypeDefinition runtimeInitializeOnLoadMethodAttribute; + + AssemblyDefinition assembly; + + public TypeReference Import() => Import(typeof(T)); + + public TypeReference Import(Type t) => assembly.MainModule.ImportReference(t); + + // constructor resolves the types and stores them in fields + public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFailed) + { + // system types + this.assembly = assembly; + + TypeReference ArraySegmentType = Import(typeof(ArraySegment<>)); + ArraySegmentConstructorReference = Resolvers.ResolveMethod(ArraySegmentType, assembly, Log, ".ctor", ref WeavingFailed); + + TypeReference ActionType = Import(typeof(Action<,>)); + ActionT_T = Resolvers.ResolveMethod(ActionType, assembly, Log, ".ctor", ref WeavingFailed); + + weaverFuseType = Import(typeof(WeaverFuse)); + weaverFuseMethod = Resolvers.ResolveMethod(weaverFuseType, assembly, Log, "Weaved", ref WeavingFailed); + + TypeReference NetworkServerType = Import(typeof(NetworkServer)); + NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed); + + TypeReference NetworkClientType = Import(typeof(NetworkClient)); + NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed); + NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed); + + TypeReference NetworkBehaviourType = Import(); + + NetworkBehaviourDirtyBitsReference = Resolvers.ResolveField(NetworkBehaviourType, assembly, Log, "syncVarDirtyBits", ref WeavingFailed); + + generatedSyncVarSetter = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter", ref WeavingFailed); + generatedSyncVarSetter_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_GameObject", ref WeavingFailed); + generatedSyncVarSetter_NetworkIdentity = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_NetworkIdentity", ref WeavingFailed); + generatedSyncVarSetter_NetworkBehaviour_T = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_NetworkBehaviour", ref WeavingFailed); + + generatedSyncVarDeserialize_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_GameObject", ref WeavingFailed); + generatedSyncVarDeserialize = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize", ref WeavingFailed); + generatedSyncVarDeserialize_NetworkIdentity = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_NetworkIdentity", ref WeavingFailed); + generatedSyncVarDeserialize_NetworkBehaviour_T = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_NetworkBehaviour", ref WeavingFailed); + + getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarGameObject", ref WeavingFailed); + getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed); + getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", ref WeavingFailed); + + sendCommandInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendCommandInternal", ref WeavingFailed); + sendRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendRPCInternal", ref WeavingFailed); + sendTargetRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendTargetRPCInternal", ref WeavingFailed); + + InitSyncObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "InitSyncObject", ref WeavingFailed); + + TypeReference RemoteProcedureCallsType = Import(typeof(RemoteCalls.RemoteProcedureCalls)); + registerCommandReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterCommand", ref WeavingFailed); + registerRpcReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterRpc", ref WeavingFailed); + + TypeReference RemoteCallDelegateType = Import(); + RemoteCallDelegateConstructor = Resolvers.ResolveMethod(RemoteCallDelegateType, assembly, Log, ".ctor", ref WeavingFailed); + + TypeReference ScriptableObjectType = Import(); + ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod( + ScriptableObjectType, assembly, Log, + md => md.Name == "CreateInstance" && md.HasGenericParameters, + ref WeavingFailed); + + TypeReference unityDebug = Import(typeof(UnityEngine.Debug)); + // these have multiple methods with same name, so need to check parameters too + logErrorReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md => + md.Name == "LogError" && + md.Parameters.Count == 1 && + md.Parameters[0].ParameterType.FullName == typeof(object).FullName, + ref WeavingFailed); + + logWarningReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md => + md.Name == "LogWarning" && + md.Parameters.Count == 1 && + md.Parameters[0].ParameterType.FullName == typeof(object).FullName, + ref WeavingFailed); + + TypeReference typeType = Import(typeof(Type)); + getTypeFromHandleReference = Resolvers.ResolveMethod(typeType, assembly, Log, "GetTypeFromHandle", ref WeavingFailed); + + TypeReference NetworkWriterPoolType = Import(typeof(NetworkWriterPool)); + GetWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Get", ref WeavingFailed); + ReturnWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Return", ref WeavingFailed); + + TypeReference readerExtensions = Import(typeof(NetworkReaderExtensions)); + readNetworkBehaviourGeneric = Resolvers.ResolveMethod(readerExtensions, assembly, Log, (md => + { + return md.Name == nameof(NetworkReaderExtensions.ReadNetworkBehaviour) && + md.HasGenericParameters; + }), + ref WeavingFailed); + + // [InitializeOnLoadMethod] + // 'UnityEditor' is not available in builds. + // we can only import this attribute if we are in an Editor assembly. + if (Helpers.IsEditorAssembly(assembly)) + { + TypeReference initializeOnLoadMethodAttributeRef = Import(typeof(InitializeOnLoadMethodAttribute)); + initializeOnLoadMethodAttribute = initializeOnLoadMethodAttributeRef.Resolve(); + } + + // [RuntimeInitializeOnLoadMethod] + TypeReference runtimeInitializeOnLoadMethodAttributeRef = Import(typeof(RuntimeInitializeOnLoadMethodAttribute)); + runtimeInitializeOnLoadMethodAttribute = runtimeInitializeOnLoadMethodAttributeRef.Resolve(); + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta new file mode 100644 index 0000000..ea2cec8 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/WeaverTypes.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2585961bf7fe4c10a9143f4087efdf6f +timeCreated: 1596486854 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/WeaverTypes.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs b/Assets/Mirror/Editor/Weaver/Writers.cs new file mode 100644 index 0000000..31a4ac7 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Writers.cs @@ -0,0 +1,360 @@ +using System; +using System.Collections.Generic; +using Mono.CecilX; +using Mono.CecilX.Cil; +// to use Mono.CecilX.Rocks here, we need to 'override references' in the +// Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.Rocks. +// otherwise we get an unknown import exception. +using Mono.CecilX.Rocks; + +namespace Mirror.Weaver +{ + // not static, because ILPostProcessor is multithreaded + public class Writers + { + // Writers are only for this assembly. + // can't be used from another assembly, otherwise we will get: + // "System.ArgumentException: Member ... is declared in another module and needs to be imported" + AssemblyDefinition assembly; + WeaverTypes weaverTypes; + TypeDefinition GeneratedCodeClass; + Logger Log; + + Dictionary writeFuncs = + new Dictionary(new TypeReferenceComparer()); + + public Writers(AssemblyDefinition assembly, WeaverTypes weaverTypes, TypeDefinition GeneratedCodeClass, Logger Log) + { + this.assembly = assembly; + this.weaverTypes = weaverTypes; + this.GeneratedCodeClass = GeneratedCodeClass; + this.Log = Log; + } + + public void Register(TypeReference dataType, MethodReference methodReference) + { + // sometimes we define multiple write methods for the same type. + // for example: + // WriteInt() // alwasy writes 4 bytes: should be available to the user for binary protocols etc. + // WriteVarInt() // varint compression: we may want Weaver to always use this for minimal bandwidth + // give the user a way to define the weaver prefered one if two exists: + // "[WeaverPriority]" attribute is automatically detected and prefered. + MethodDefinition methodDefinition = methodReference.Resolve(); + bool priority = methodDefinition.HasCustomAttribute(); + // if (priority) Log.Warning($"Weaver: Registering priority Write<{dataType.FullName}> with {methodReference.FullName}.", methodReference); + + // Weaver sometimes calls Register for multiple times because we resolve assemblies multiple times. + // if the function name is the same: always use the latest one. + // if the function name differes: use the priority one. + if (writeFuncs.TryGetValue(dataType, out MethodReference existingMethod) && // if it was already defined + existingMethod.FullName != methodReference.FullName && // and this one is a different name + !priority) // and it's not the priority one + { + return; // then skip + } + + // we need to import type when we Initialize Writers so import here in case it is used anywhere else + TypeReference imported = assembly.MainModule.ImportReference(dataType); + writeFuncs[imported] = methodReference; + } + + void RegisterWriteFunc(TypeReference typeReference, MethodDefinition newWriterFunc) + { + Register(typeReference, newWriterFunc); + GeneratedCodeClass.Methods.Add(newWriterFunc); + } + + // Finds existing writer for type, if non exists trys to create one + public MethodReference GetWriteFunc(TypeReference variable, ref bool WeavingFailed) + { + if (writeFuncs.TryGetValue(variable, out MethodReference foundFunc)) + return foundFunc; + + // this try/catch will be removed in future PR and make `GetWriteFunc` throw instead + try + { + TypeReference importedVariable = assembly.MainModule.ImportReference(variable); + return GenerateWriter(importedVariable, ref WeavingFailed); + } + catch (GenerateWriterException e) + { + Log.Error(e.Message, e.MemberReference); + WeavingFailed = true; + return null; + } + } + + //Throws GenerateWriterException when writer could not be generated for type + MethodReference GenerateWriter(TypeReference variableReference, ref bool WeavingFailed) + { + if (variableReference.IsByReference) + { + throw new GenerateWriterException($"Cannot pass {variableReference.Name} by reference", variableReference); + } + + // Arrays are special, if we resolve them, we get the element type, + // e.g. int[] resolves to int + // therefore process this before checks below + if (variableReference.IsArray) + { + if (variableReference.IsMultidimensionalArray()) + { + throw new GenerateWriterException($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference); + } + TypeReference elementType = variableReference.GetElementType(); + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArray), ref WeavingFailed); + } + + if (variableReference.Resolve()?.IsEnum ?? false) + { + // serialize enum as their base type + return GenerateEnumWriteFunc(variableReference, ref WeavingFailed); + } + + // check for collections + if (variableReference.Is(typeof(ArraySegment<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteArraySegment), ref WeavingFailed); + } + if (variableReference.Is(typeof(List<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList), ref WeavingFailed); + } + if (variableReference.Is(typeof(HashSet<>))) + { + GenericInstanceType genericInstance = (GenericInstanceType)variableReference; + TypeReference elementType = genericInstance.GenericArguments[0]; + + return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteHashSet), ref WeavingFailed); + } + + // handle both NetworkBehaviour and inheritors. + // fixes: https://github.com/MirrorNetworking/Mirror/issues/2939 + if (variableReference.IsDerivedFrom() || variableReference.Is()) + { + return GetNetworkBehaviourWriter(variableReference); + } + + // check for invalid types + TypeDefinition variableDefinition = variableReference.Resolve(); + if (variableDefinition == null) + { + throw new GenerateWriterException($"{variableReference.Name} is not a supported type. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsDerivedFrom()) + { + throw new GenerateWriterException($"Cannot generate writer for component type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableReference.Is()) + { + throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableReference.Is()) + { + throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.HasGenericParameters) + { + throw new GenerateWriterException($"Cannot generate writer for generic type {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsInterface) + { + throw new GenerateWriterException($"Cannot generate writer for interface {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + if (variableDefinition.IsAbstract) + { + throw new GenerateWriterException($"Cannot generate writer for abstract class {variableReference.Name}. Use a supported type or provide a custom writer", variableReference); + } + + // generate writer for class/struct + return GenerateClassOrStructWriterFunction(variableReference, ref WeavingFailed); + } + + MethodReference GetNetworkBehaviourWriter(TypeReference variableReference) + { + // all NetworkBehaviours can use the same write function + if (writeFuncs.TryGetValue(weaverTypes.Import(), out MethodReference func)) + { + // register function so it is added to writer + // use Register instead of RegisterWriteFunc because this is not a generated function + Register(variableReference, func); + + return func; + } + else + { + // this exception only happens if mirror is missing the WriteNetworkBehaviour method + throw new MissingMethodException($"Could not find writer for NetworkBehaviour"); + } + } + + MethodDefinition GenerateEnumWriteFunc(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + + MethodReference underlyingWriter = GetWriteFunc(variable.Resolve().GetEnumUnderlyingType(), ref WeavingFailed); + + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Call, underlyingWriter); + + worker.Emit(OpCodes.Ret); + return writerFunc; + } + + MethodDefinition GenerateWriterFunc(TypeReference variable) + { + string functionName = $"_Write_{variable.FullName}"; + // create new writer for this type + MethodDefinition writerFunc = new MethodDefinition(functionName, + MethodAttributes.Public | + MethodAttributes.Static | + MethodAttributes.HideBySig, + weaverTypes.Import(typeof(void))); + + writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import())); + writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, variable)); + writerFunc.Body.InitLocals = true; + + RegisterWriteFunc(variable, writerFunc); + return writerFunc; + } + + MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variable, ref bool WeavingFailed) + { + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + + if (!variable.Resolve().IsValueType) + WriteNullCheck(worker, ref WeavingFailed); + + if (!WriteAllFields(variable, worker, ref WeavingFailed)) + return null; + + worker.Emit(OpCodes.Ret); + return writerFunc; + } + + void WriteNullCheck(ILProcessor worker, ref bool WeavingFailed) + { + // if (value == null) + // { + // writer.WriteBoolean(false); + // return; + // } + // + + Instruction labelNotNull = worker.Create(OpCodes.Nop); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Brtrue, labelNotNull); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I4_0); + worker.Emit(OpCodes.Call, GetWriteFunc(weaverTypes.Import(), ref WeavingFailed)); + worker.Emit(OpCodes.Ret); + worker.Append(labelNotNull); + + // write.WriteBoolean(true); + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldc_I4_1); + worker.Emit(OpCodes.Call, GetWriteFunc(weaverTypes.Import(), ref WeavingFailed)); + } + + // Find all fields in type and write them + bool WriteAllFields(TypeReference variable, ILProcessor worker, ref bool WeavingFailed) + { + foreach (FieldDefinition field in variable.FindAllPublicFields()) + { + MethodReference writeFunc = GetWriteFunc(field.FieldType, ref WeavingFailed); + // need this null check till later PR when GetWriteFunc throws exception instead + if (writeFunc == null) { return false; } + + FieldReference fieldRef = assembly.MainModule.ImportReference(field); + + worker.Emit(OpCodes.Ldarg_0); + worker.Emit(OpCodes.Ldarg_1); + worker.Emit(OpCodes.Ldfld, fieldRef); + worker.Emit(OpCodes.Call, writeFunc); + } + + return true; + } + + MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeReference elementType, string writerFunction, ref bool WeavingFailed) + { + + MethodDefinition writerFunc = GenerateWriterFunc(variable); + + MethodReference elementWriteFunc = GetWriteFunc(elementType, ref WeavingFailed); + MethodReference intWriterFunc = GetWriteFunc(weaverTypes.Import(), ref WeavingFailed); + + // need this null check till later PR when GetWriteFunc throws exception instead + if (elementWriteFunc == null) + { + Log.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable); + WeavingFailed = true; + return writerFunc; + } + + ModuleDefinition module = assembly.MainModule; + TypeReference readerExtensions = module.ImportReference(typeof(NetworkWriterExtensions)); + MethodReference collectionWriter = Resolvers.ResolveMethod(readerExtensions, assembly, Log, writerFunction, ref WeavingFailed); + + GenericInstanceMethod methodRef = new GenericInstanceMethod(collectionWriter); + methodRef.GenericArguments.Add(elementType); + + // generates + // reader.WriteArray(array); + + ILProcessor worker = writerFunc.Body.GetILProcessor(); + worker.Emit(OpCodes.Ldarg_0); // writer + worker.Emit(OpCodes.Ldarg_1); // collection + + worker.Emit(OpCodes.Call, methodRef); // WriteArray + + worker.Emit(OpCodes.Ret); + + return writerFunc; + } + + // Save a delegate for each one of the writers into Writer{T}.write + internal void InitializeWriters(ILProcessor worker) + { + ModuleDefinition module = assembly.MainModule; + + TypeReference genericWriterClassRef = module.ImportReference(typeof(Writer<>)); + + System.Reflection.FieldInfo fieldInfo = typeof(Writer<>).GetField(nameof(Writer.write)); + FieldReference fieldRef = module.ImportReference(fieldInfo); + TypeReference networkWriterRef = module.ImportReference(typeof(NetworkWriter)); + TypeReference actionRef = module.ImportReference(typeof(Action<,>)); + MethodReference actionConstructorRef = module.ImportReference(typeof(Action<,>).GetConstructors()[0]); + + foreach (KeyValuePair kvp in writeFuncs) + { + TypeReference targetType = kvp.Key; + MethodReference writeFunc = kvp.Value; + + // create a Action delegate + worker.Emit(OpCodes.Ldnull); + worker.Emit(OpCodes.Ldftn, writeFunc); + GenericInstanceType actionGenericInstance = actionRef.MakeGenericInstanceType(networkWriterRef, targetType); + MethodReference actionRefInstance = actionConstructorRef.MakeHostInstanceGeneric(assembly.MainModule, actionGenericInstance); + worker.Emit(OpCodes.Newobj, actionRefInstance); + + // save it in Writer.write + GenericInstanceType genericInstance = genericWriterClassRef.MakeGenericInstanceType(targetType); + FieldReference specializedField = fieldRef.SpecializeField(assembly.MainModule, genericInstance); + worker.Emit(OpCodes.Stsfld, specializedField); + } + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs.meta b/Assets/Mirror/Editor/Weaver/Writers.cs.meta new file mode 100644 index 0000000..1bec2a8 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Writers.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a90060ad76ea044aba613080dd922709 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Weaver/Writers.cs + uploadId: 736421 diff --git a/Assets/Mirror/Editor/Welcome.cs b/Assets/Mirror/Editor/Welcome.cs new file mode 100644 index 0000000..49bd379 --- /dev/null +++ b/Assets/Mirror/Editor/Welcome.cs @@ -0,0 +1,23 @@ +// Shows either a welcome message, only once per session. +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace Mirror +{ + static class Welcome + { + [InitializeOnLoadMethod] + static void OnInitializeOnLoad() + { + // InitializeOnLoad is called on start and after each rebuild, + // but we only want to show this once per editor session. + if (!SessionState.GetBool("MIRROR_WELCOME", false)) + { + SessionState.SetBool("MIRROR_WELCOME", true); + Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Mirror | mirror-networking.com | discord.gg/N9QVxbM"); + } + } + } +} +#endif diff --git a/Assets/Mirror/Editor/Welcome.cs.meta b/Assets/Mirror/Editor/Welcome.cs.meta new file mode 100644 index 0000000..82dd027 --- /dev/null +++ b/Assets/Mirror/Editor/Welcome.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 180619c3887314f56bf396769c0a23ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Editor/Welcome.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples.meta b/Assets/Mirror/Examples.meta new file mode 100644 index 0000000..b594a81 --- /dev/null +++ b/Assets/Mirror/Examples.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a08b1f591326642d1b140fc818c9c6b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels.meta b/Assets/Mirror/Examples/AdditiveLevels.meta new file mode 100644 index 0000000..d8d6382 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2da9e7acc6ad1648b0ff0849ef4c283 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials.meta new file mode 100644 index 0000000..7a5d3cd --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60c31680133898d43822d2d9eae56494 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat new file mode 100644 index 0000000..6531132 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: CubeSphere + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta new file mode 100644 index 0000000..80ffe6c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 38950807c6bf6454dbef567827b770b6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/CubeSphere.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat new file mode 100644 index 0000000..38c9a40 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Ground + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.027055884, g: 0.09279272, b: 0.3018868, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta new file mode 100644 index 0000000..76a107d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 20d755ab53045e545ab0b6e59c710ed9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/Ground.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat new file mode 100644 index 0000000..a394fe1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat.meta new file mode 100644 index 0000000..0b18299 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 6b7039502d1528a4db29c4d43d159b01 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/Player.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat new file mode 100644 index 0000000..f0d5fce --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Portal + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0.54901963, g: 0.54901963, b: 1, a: 0.23529412} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat.meta new file mode 100644 index 0000000..870aa3c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 3500dce637708024da2f2e45e4f71cd3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/Portal.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat new file mode 100644 index 0000000..7d59ae9 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat @@ -0,0 +1,104 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Skybox + m_Shader: {fileID: 104, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BackTex: + m_Texture: {fileID: 2800000, guid: 1566af6e663684dbd85aa5fb32fd9148, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DownTex: + m_Texture: {fileID: 2800000, guid: 9ffeeee1accdc4b4faf2b3e27b226340, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _FrontTex: + m_Texture: {fileID: 2800000, guid: ca928ef0e269448ba82388eb41d48544, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _LeftTex: + m_Texture: {fileID: 2800000, guid: e5a0eeef6a2514a78b267405d686fe09, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _RightTex: + m_Texture: {fileID: 2800000, guid: 4c8911efa34c845f28fbac86385a1b41, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _UpTex: + m_Texture: {fileID: 2800000, guid: bd9ad886b003944169e7ce1286756940, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _Exposure: 1 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _Rotation: 0 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _Tint: {r: 0.5, g: 0.5, b: 0.5, a: 0.5} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta new file mode 100644 index 0000000..113219c --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 81f714daf7144784b8a2f42f1cd30927 +timeCreated: 1497127647 +licenseType: Store +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/Skybox.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat b/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat new file mode 100644 index 0000000..7ec88f5 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: StartPoint + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 0.6236605, b: 0, a: 0.5372549} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta b/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta new file mode 100644 index 0000000..886c964 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: ec3b6ac9651c31248bcfbf695e6f597a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Materials/StartPoint.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta new file mode 100644 index 0000000..0bb6a54 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9d4b9adc9613a04fb715c64d3d2dcf8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab new file mode 100644 index 0000000..e0c3074 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab @@ -0,0 +1,132 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3181899219042528418 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3181899219042528419} + - component: {fileID: 3181899219042528430} + - component: {fileID: 3181899219042528417} + - component: {fileID: 3181899219042528416} + - component: {fileID: -1828993248307539358} + - component: {fileID: 96969086124788804} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3181899219042528419 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3181899219042528430 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3181899219042528417 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 38950807c6bf6454dbef567827b770b6, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!65 &3181899219042528416 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &-1828993248307539358 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1959795484 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &96969086124788804 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3181899219042528418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta new file mode 100644 index 0000000..e7868f6 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7c6a0a278eba11e44b9a86cd4da603df +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/Cube.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab new file mode 100644 index 0000000..086193b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab @@ -0,0 +1,152 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7349408984269008055 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7349408984269008052} + - component: {fileID: 7349408984269008059} + - component: {fileID: 7349408984269008058} + - component: {fileID: 7349408984269008053} + - component: {fileID: 7349408984269008063} + - component: {fileID: 7349408984269008062} + - component: {fileID: 7349408984269008057} + - component: {fileID: 7349408984269008056} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7349408984269008052 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7349408984269008059 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &7349408984269008058 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 20d755ab53045e545ab0b6e59c710ed9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &7349408984269008053 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!65 &7349408984269008063 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 6, z: 0.05} + m_Center: {x: 0, y: 3, z: -5} +--- !u!65 &7349408984269008062 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 6, z: 0.05} + m_Center: {x: 0, y: 3, z: 5} +--- !u!65 &7349408984269008057 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 6, z: 10} + m_Center: {x: 5, y: 3, z: 0} +--- !u!65 &7349408984269008056 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7349408984269008055} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 6, z: 10} + m_Center: {x: -5, y: 3, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta new file mode 100644 index 0000000..c8128fb --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 4fdcc4aa5c669b348a5954a92f5e8e89 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/Plane.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab new file mode 100644 index 0000000..16078eb --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab @@ -0,0 +1,385 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1724664263041697580 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7513987664611104733} + - component: {fileID: 3866048407219963700} + - component: {fileID: 6667391912482377964} + m_Layer: 0 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7513987664611104733 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 962190737825349125} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3866048407219963700 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6667391912482377964 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5620029719931856626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 962190737825349125} + - component: {fileID: 8168211270351413936} + - component: {fileID: 5601443051240418659} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &962190737825349125 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7513987664611104733} + m_Father: {fileID: 464867598898769114} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8168211270351413936 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5601443051240418659 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6b7039502d1528a4db29c4d43d159b01, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &7619140271685878370 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 464867598898769114} + - component: {fileID: 5674344380471455553} + - component: {fileID: 6346220616177654294} + - component: {fileID: -903079073849018483} + - component: {fileID: -1734969889957956087} + - component: {fileID: 5462452979215896872} + - component: {fileID: -2422551836510166228} + - component: {fileID: 1763152038191860132} + - component: {fileID: 1747637013460943425} + m_Layer: 0 + m_Name: PlayerReliable + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &464867598898769114 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 962190737825349125} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5674344380471455553 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 793773322 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &6346220616177654294 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8ff3ba0becae47b8b9381191598957c8, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 464867598898769114} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + onlySyncOnChangeCorrectionMultiplier: 2 + rotationSensitivity: 0.01 + positionPrecision: 0.01 + scalePrecision: 0.01 +--- !u!114 &-903079073849018483 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71ac1e35462ffad469e77d1c2fe6c9f3, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + offset: {x: 0, y: 3, z: -8} + rotation: {x: 10, y: 0, z: 0} +--- !u!114 &-1734969889957956087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 497221e839119e34b897d6c497cbc8e5, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 5462452979215896872} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!143 &5462452979215896872 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &-2422551836510166228 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1763152038191860132 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &1747637013460943425 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab.meta new file mode 100644 index 0000000..3c0b001 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9f0094c1325091d42a558274b947221f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerReliable.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab new file mode 100644 index 0000000..556d419 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab @@ -0,0 +1,385 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1724664263041697580 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7513987664611104733} + - component: {fileID: 3866048407219963700} + - component: {fileID: 6667391912482377964} + m_Layer: 0 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7513987664611104733 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 962190737825349125} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3866048407219963700 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6667391912482377964 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1724664263041697580} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5620029719931856626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 962190737825349125} + - component: {fileID: 8168211270351413936} + - component: {fileID: 5601443051240418659} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &962190737825349125 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7513987664611104733} + m_Father: {fileID: 464867598898769114} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8168211270351413936 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5601443051240418659 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5620029719931856626} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6b7039502d1528a4db29c4d43d159b01, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &7619140271685878370 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 464867598898769114} + - component: {fileID: 5674344380471455553} + - component: {fileID: -903079073849018483} + - component: {fileID: 5462452979215896872} + - component: {fileID: -2422551836510166228} + - component: {fileID: 1763152038191860132} + - component: {fileID: 1747637013460943425} + - component: {fileID: -8751611566496799529} + - component: {fileID: -156360445163968950} + m_Layer: 0 + m_Name: PlayerUnreliable + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &464867598898769114 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 962190737825349125} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5674344380471455553 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2403673814 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-903079073849018483 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71ac1e35462ffad469e77d1c2fe6c9f3, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + offset: {x: 0, y: 3, z: -8} + rotation: {x: 10, y: 0, z: 0} +--- !u!143 &5462452979215896872 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &-2422551836510166228 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1763152038191860132 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &1747637013460943425 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &-8751611566496799529 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 464867598898769114} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-156360445163968950 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7619140271685878370} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f81b59082839c2e40938767457bb91ae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 5462452979215896872} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab.meta new file mode 100644 index 0000000..8b00943 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: bf7debf03638cd941a45060adab91cb2 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/PlayerUnreliable.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab new file mode 100644 index 0000000..2439e04 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab @@ -0,0 +1,246 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1098173225717622925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1098173225717622921} + - component: {fileID: 1098173225717622922} + - component: {fileID: 1098173225717622923} + - component: {fileID: 1098173225717622924} + - component: {fileID: 3141292696673982546} + - component: {fileID: 5948271423698091598} + m_Layer: 0 + m_Name: Portal + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1098173225717622921 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: 0} + m_LocalScale: {x: 2, y: 2, z: 2} + m_Children: + - {fileID: 1355348187805494562} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1098173225717622922 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1098173225717622923 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 3500dce637708024da2f2e45e4f71cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!136 &1098173225717622924 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.2 + m_Height: 1 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &3141292696673982546 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3230666986 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &5948271423698091598 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1098173225717622925} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0e680878006965146a8f9d85834c4d1c, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + destinationScene: + startPosition: {x: 0, y: 1.02, z: 0} + label: {fileID: 8197110483235692531} + labelText: +--- !u!1 &5961932215084527574 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1355348187805494562} + - component: {fileID: 5428053421152709616} + - component: {fileID: 3243959486819493908} + - component: {fileID: 8197110483235692531} + m_Layer: 9 + m_Name: Label_TMP + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1355348187805494562 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5961932215084527574} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1098173225717622921} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 1.5} + m_SizeDelta: {x: 20, y: 5} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &5428053421152709616 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5961932215084527574} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &3243959486819493908 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5961932215084527574} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cc58300ee45438a418d9e32957fdc0c0, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!102 &8197110483235692531 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5961932215084527574} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 0.05 + m_LineSpacing: 1 + m_Anchor: 4 + m_Alignment: 1 + m_TabSize: 4 + m_FontSize: 100 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta new file mode 100644 index 0000000..8aaa104 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c624c75494b4d7d4086b9212f897e56a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/Portal.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab new file mode 100644 index 0000000..75c943a --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab @@ -0,0 +1,132 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2188792038427236743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2188792038427236742} + - component: {fileID: 2188792038427236747} + - component: {fileID: 2188792038427236744} + - component: {fileID: 2188792038427236745} + - component: {fileID: -5172514306435102607} + - component: {fileID: 1758063572567377699} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2188792038427236742 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2188792038427236747 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2188792038427236744 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 38950807c6bf6454dbef567827b770b6, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!135 &2188792038427236745 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &-5172514306435102607 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3721049776 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &1758063572567377699 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2188792038427236743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + color: + serializedVersion: 2 + rgba: 4278190080 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta new file mode 100644 index 0000000..7520fdc --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e588080aa542be54d9ca9d5c734dc9ee +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/Sphere.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab new file mode 100644 index 0000000..c70961b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab @@ -0,0 +1,85 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7582855647636897216 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7582855647636897223} + - component: {fileID: 7582855647636897221} + - component: {fileID: 7582855647636897222} + m_Layer: 0 + m_Name: StartPoint + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7582855647636897223 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7582855647636897216} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 2, y: 0.05, z: 2} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7582855647636897221 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7582855647636897216} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &7582855647636897222 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7582855647636897216} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ec3b6ac9651c31248bcfbf695e6f597a, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta new file mode 100644 index 0000000..5041571 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 849c125c9d8094249b3c664da1cd143a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Prefabs/StartPoint.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt b/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt new file mode 100644 index 0000000..9f5f0f1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt @@ -0,0 +1 @@ +Setup details at https://mirror-networking.gitbook.io/docs/examples/additive-levels \ No newline at end of file diff --git a/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt.meta b/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt.meta new file mode 100644 index 0000000..b07a423 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e0b006e68a5390c42a2ac1413c98e72f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/ReadMe.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta new file mode 100644 index 0000000..2817b8a --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a6d39d823db54d43925eb65b4ffec55 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity new file mode 100644 index 0000000..ecdd5e2 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity @@ -0,0 +1,510 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &185921126 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 185921129} + - component: {fileID: 185921128} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &185921128 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 185921126} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 15 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &185921129 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 185921126} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1040404844 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1040404847} + - component: {fileID: 1040404846} + - component: {fileID: 1040404845} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1040404845 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1040404844} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1040404846 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1040404844} + m_CullTransparentMesh: 0 +--- !u!224 &1040404847 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1040404844} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1300359894} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1074858613 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1074858617} + - component: {fileID: 1074858616} + - component: {fileID: 1074858615} + - component: {fileID: 1074858614} + - component: {fileID: 1074858618} + m_Layer: 0 + m_Name: Network + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1074858614 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1074858613} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1074858615 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1074858613} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1074858616 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1074858613} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01eafa8309a0894479f0f87ae1a9c30f, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity + onlineScene: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity + offlineSceneLoadDelay: 0 + transport: {fileID: 1074858615} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 7619140271685878370, guid: 9f0094c1325091d42a558274b947221f, + type: 3} + autoCreatePlayer: 0 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + additiveScenes: + - Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity + - Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity + fadeInOut: {fileID: 1300359890} +--- !u!4 &1074858617 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1074858613} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1300359894} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1074858618 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1074858613} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b979f26c95d34324ba005bfacfa9c4fc, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1300359889 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1300359894} + - component: {fileID: 1300359893} + - component: {fileID: 1300359892} + - component: {fileID: 1300359890} + m_Layer: 5 + m_Name: FadeCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1300359890 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1300359889} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 363a8867bb9c7b845a73233566df8c1e, type: 3} + m_Name: + m_EditorClassIdentifier: + panelImage: {fileID: 1040404845} + fadeInTime: 2 + fadeOutTime: 2 +--- !u!114 &1300359892 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1300359889} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1300359893 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1300359889} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1300359894 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1300359889} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1040404847} + m_Father: {fileID: 1074858617} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity.meta new file mode 100644 index 0000000..893d722 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9959d9d8e637be64dab77006a85135c1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOffline.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.meta new file mode 100644 index 0000000..4baac2e --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7fc791c940e4cb94fa7890b86c12bb40 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity new file mode 100644 index 0000000..ab819d3 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity @@ -0,0 +1,816 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 1 + m_FogColor: {r: 0.0627451, g: 0.08235294, b: 0.18431373, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.35537556, g: 0.3689654, b: 0.6226415, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 2100000, guid: 81f714daf7144784b8a2f42f1cd30927, type: 2} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.2328035, g: 0.23442134, b: 0.27287462, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000002, guid: 71d66be797c1eb44bab0797662b33cbc, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &203151409 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 203151411} + - component: {fileID: 203151410} + m_Layer: 0 + m_Name: Directional Light (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &203151410 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 203151409} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &203151411 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 203151409} + m_LocalRotation: {x: 0.2588191, y: 0, z: 0, w: 0.9659258} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 30, y: 0, z: 0} +--- !u!1 &413994573 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 413994576} + - component: {fileID: 413994575} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &413994575 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 413994573} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 15 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &413994576 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 413994573} + m_LocalRotation: {x: 0.3420201, y: 0, z: 0, w: 0.9396927} + m_LocalPosition: {x: 0, y: 30, z: -30} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 40, y: 0, z: 0} +--- !u!1 &587543889 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 587543891} + - component: {fileID: 587543890} + m_Layer: 0 + m_Name: Directional Light (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &587543890 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 587543889} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &587543891 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 587543889} + m_LocalRotation: {x: -0.12940955, y: 0.8365163, z: -0.22414392, w: -0.48296294} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 30, y: 240, z: 0} +--- !u!1 &1110529627 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1110529629} + - component: {fileID: 1110529628} + m_Layer: 0 + m_Name: Directional Light (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1110529628 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1110529627} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1110529629 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1110529627} + m_LocalRotation: {x: 0.12940954, y: 0.8365163, z: -0.22414392, w: 0.48296285} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 30, y: 120, z: 0} +--- !u!1 &1309024824 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1309024826} + - component: {fileID: 1309024825} + m_Layer: 0 + m_Name: Directional Light (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1309024825 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1309024824} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1309024826 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1309024824} + m_LocalRotation: {x: 0, y: 0.9659258, z: -0.2588191, w: 0} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 30, y: 180, z: 0} +--- !u!1 &1606864533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1606864535} + - component: {fileID: 1606864534} + m_Layer: 0 + m_Name: Directional Light (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1606864534 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1606864533} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1606864535 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1606864533} + m_LocalRotation: {x: 0.22414392, y: 0.48296294, z: -0.12940955, w: 0.8365163} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 30, y: 60, z: 0} +--- !u!1 &1841150988 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1841150991} + - component: {fileID: 1841150990} + - component: {fileID: 1841150989} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1841150989 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1841150988} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1841150990 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1841150988} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1841150991 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1841150988} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1938492451 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1938492453} + - component: {fileID: 1938492452} + m_Layer: 0 + m_Name: Directional Light (6) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1938492452 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1938492451} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.33161265, g: 0.3338098, b: 0.33962262, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1938492453 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1938492451} + m_LocalRotation: {x: -0.22414392, y: 0.48296294, z: -0.12940955, w: -0.8365163} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 30, y: 300, z: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity.meta new file mode 100644 index 0000000..5cba1ea --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 3c63960543989ea41ba3d3fb04d6dcf3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/LightingData.asset b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/LightingData.asset new file mode 100644 index 0000000000000000000000000000000000000000..8824b1c57743df35663123435c0adbe9313c8ffd GIT binary patch literal 19648 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

+r#* z$tkDCxYDWohmY1Oqe@n++3Jb9$whOm22K;EbA2tSZB((ZweO@B?fFlfRd3-`(i_aE zR{GajmKRb}MT?WkU)YLrU07eT4?JXzWX8Q~KOPHAvRcmAQY!P#_gQwB@)h2$t(?+m zOb*jybE=HpR%eJe{UYE|TK%l5AgA?(lC@)c(?cseaptr4N;AQSUlkXl$2OZjooAQk z9IECV2N|3gc($asM+BE5Y?>iWh@9yLjQg@@&D}kRg$7Erbo#KE%k|`yuJDFJjSEnJ zb~%spJAkRO26t>{U48(-%ntx8+Mxs9;~v%Si8vU5E&XCs(*N2h$MOb!S?}Q10bF;} zOKHHDEyD*{zuvNq_x29)013&jb{3~L@Ef-4*TicHFJWWTMS!$PQ5~^x0J|ciTE964*(~Px z!g0l~K-1*go^(T;8CB9vM4o$b*o6P96PkiRwW@8Sm)pqY&mTR- ziK_l{+cnU#F>uUHs0{4!1iuNW+UrfbVw{yVw8{qEy-)*AJi++n0ey~A3jcqCY&@mv zx=naGLE1U8Zv0Io>x?Yo@Fqfee2*rHa?T-dFHhLSFLq5XHc}EiHo>}-F2VkM{EQ|! z&Z3CKKWd)Tz5nnOiMWL{gD?u)S>twXmVMUax$_UoTD*t?;sm9bj0wD*LyhOEh=(og zwQ531qYY9V3+J|4?PFYC%R^N0Sl0dpzq;kVAiO0R2e;C5#Sf{If)kj%bLF;BqpEUv zLm?T?SQ5&RSSnicr6X(#Bfo_=(OE*>NhA#Yl@dBgFBV#RB$YDjhsTU|b8lNh@WfS))pARTWxZ`upMXjZ^H+R$o&AK`Na&-f9A4e@up?KK z(%p6%DQmnsp~lFJQxa1AHKKBY)5m@pRjHfu_(oqQ8DDnYj#a->IEZ&rBQy(O5ifOa z-x3TBiM(*)uOXYS4-1>7xfgQzG`UZT*@9O;2#V5BY`MOmf zxbaF2M}pcP-Oe2Vqpl9Fd6(#xzKel>#NPWq#2wiaW~v?~_$yA3f#SXZl>&oK$ao>Rm2Y4xZDA#tpY$I!^S&akv>vp9-ud4GJ_MwC+~~$1m;908Ut>x z5xM8trY6h3m&l9a^VNdg)%N_K{kONzLgd=rDFdUkC_*G+piORMp#x=!fYqw z=q?MIAMH;*kBvfp%^(2X)X$aGC;7!JoGJVf?ql7;=7c>~HH< z_cG?$dQ=#2R}H+1^s=gdf16K8I?r!0+yZXbmDL+Ane`Zbevh$Kv2|+6sE*WA3oc@j zp>aJc$Vgz(^Pk#>U>yxhrV(R+9#Rle8-HjlYj$7K|GL5<3naW{B*GNFz^# zD1%s~ALBT}Ptv+R0`YY6W?G;~seSW78>SdR(AADwsk8lG@EtlNU=7RtO-2EVA5-iH z!ta_W2g!*#6loe`PAN>hbgLtGY3gjzxGAujmlXtL;#evfQ5W{Y`S~dW;9cefvNH?b z<(I!AZ~xB^h*`T;C0`4E_IO~t8U*Bgyxbs~n~RaXis83;j z`=8@ikdm{)nKBJ8RODBC6%$vneCg-+-y8SgYlEon zXPIIz6UQrl|4^~tE_a~^r? z%Q;( zHbCk-uCtd20PQR348S^a@qQ}k7CU3uzY9k$HYL0dV(mD~2+J*<_ffSOh5L_1LiSxp z_#$^{Q6P8&RruXe6-Z_P${(caroaf_5Cci%jHrE!xys7oZNXOx8h;t4^{Pm=7kHN`GnZfz%`3$%ja*wbVn`QhT zFb~(1M@4f2TpB26XYS4osv^KFj87czjBp2JlVwu{5!m}v>{)6+V^Dl0TV!#%Ou$O1 z(3;e&;y6w=`TKR$=YM(>3PRWW@OcgPqjSc03(xLFR~A~a`WGZsHk1!0Ig;iHXA70Y z*B3;lv&MfOaNP*DzfUemu&OwDiuP7#YDJ`{4LQ{yLjL4-53PrOw=@Lh#Zsrx~IDcC*Rr?p+ubU#8knC@xv%{-l&r{vT@IgYGOPJ$qbu z#~)@R)Dnd~=vpLY+K5?vQl|&9R|rD0WOiYE?3G}U7XT;903}|>W!_a})}i+*Mj`$f zBk=(=EuI4noIpPXn0k3cs7!quloLU&!5+_?$SDQjz#8FUUS-~>)jWJw;r)0Kgy-2H zT}QZ!7~eQ%2)5U00>BVCSc!cIUUBZw9@v)egCh^^@P9O_CdJJ*0#Yi3J9moncrOjv zi=o!7PmVk(a1J!-*IKQtC+G8lfTlE z64P;)G!!KvHLOHRU=r$tbVS?(e9!?c4cb{5{ae(N-HPg&x4JkO;aLh?3zUP^CBwFa zbFEdM;)JU4da>0(Lr%;KgrAEf_R8f|yre%z^iFrKba`Zdibect$6@Y2_F_0vPJX^U zoY7_IYZwgu*vrTl$_u$g=M%;LSXYm}NoBydp#twS)9g!10`p>eO1)?a{$aRlrlP7` z(6DRTeH@OqCr`#JicYRw-U%@5zNs^4y=)OGi^CCqWm4oqo_c@P{JRyIy1k)UOi!<- zsD@@=wjvnjZD`usVCTG=!=$e+sx~99DMC3DnzfceuXgGuMz~VuJ8B|juZLvnIkniL zR|sNYoBDzl&jIIzJE-Fz3cW=^s1eqIwk7JM1Az)DArj%=k^fQk7VqDKN5w2kYoDa0 zQPP0KMM!$=HJJnV>tvVfC$%{LW+S_UN4Kw&d3}s`X>_H*Y&@tKO2m8BPS_SecWwiT z)ULFB32H-BDHA4tw>UYAlOKWpmy@&x$1RBG6$NL~KdAjc{hP>!XBjpnAkNJmOh0}H zlGmFbq$yC_MH9&+qplZKb+11FTP9tcV8FiIWa~zP8;B$1B3)mL1XU}#e*{RlCqbv& z4n4U8z7TbEKJq$o7oz(AVfBo40Bn`kaihl@=XeXX4Vd1{@wZ*58)Js#(>y9tyHOue z<9-TS8u^cfNtFV)e@o{Ige==qxqRc%1RnAAyLyBXkYwVP)%l#oZQw@4f(KTqYf@oe zjy}|Bm$B^2)~FpuEH-v*7?Y$z)t>;>#g+kVy7g5A-%IwTR^%gJZ3!I6|2tu4Y?%=? zxb}dzB5}{Amx9QI z=P3XqU#j^kIB~Og{&8ho?gIJaZ7+apUL-J?0N@s@VJ|IIdo*f!AZZgNR7r8-{P602l^QqJG>1~Cu zM>gArwGk&Af0{C*gx%GKBYU5)nFAo5Z98Mn_${CUmkCLO#9G&7nse6X5a z>XwaO&rf8%5Kr`L-Y#q#5Ir%~VPfhsdqFR#OaGSfl$!7w+PQmSrw@a3`Rlr^q_xGW zIWx*{inJ@MGjRMPHddezYBOE?J}#VZe2*%|zA>`8;pl$Qg>YjwBJ@Z4Y_isl|Vv&)wa-R6#+P|4!XM$Cutp@Ra-z=gC zd|GZdyp$aho5J#5Lj)E}Vu6bH5c z<6s9&*n$Cmm|5z2dTNZ%9o%I7uL=9wNPKbd?7c9ItTKxLaIzrkXGTapoz0!3FNIYm z30I&;3o1X*Uaq<>_++^#A#xv5ERk0PLb;RSt3IFWWKs(>PH5{f&)MKC8xemk=1@Dd zYXC4&Vp1$hY0l*=g5@nvav-zDyYYu&BauJ`&kck`6^u~FkpIQgGzPG($R)!swC;@m zN7PG_Rs}Bgh3@P+5Bsvn{Lw2ERgdu(7J_BOaHWhs)%DtAJGB$|037P>o{#z|>b6k3XOgtzNJ^^g_?N=+_x5nSAW`}s@`UP7%QB%mhY^@4?J4;#yRw0k5)U2GFL5^2w?!RGFs5n9)~#W;8s$tmaXwl4JSFQg_LM8SqpZOn zHZA!~8i&t-g31b#{M022W2+rs)Q+{_S%DH-5-# zeetWFsMvoXiMIQdC-8gS%s2+5v_r9kf)7$P=qly`@JN&K1QJ&rh(7mIkeZ`9Og!PW z6LwdW6LP@jvjVjf>Nd_arqFU3|A-9kVfW-llI`*KlD>j$Pi3Sj>%y6Yduyz3ZFmtjH7!mMvwpqzP`rM& z15=MT0563Mhuv<%hjS5Y#!%A3QC6MhG;lsOnnY3(5(9XsACrYgA{gp#@?!)?#n%DCihceyRyOpHCx-en%Gpk`Q-HXbM?H_CvJI(QUYe zT4<_1$zqbfquM7ud5+CNNV$Q$A~cDHAbE&TC>uXDpLAHzDz_=XTf}+S$<$yj6_c); zy27ku(m1faugATm7x;R0bbhIa&jjfERjx_R?6}%>jHH=FJ7SCF679eFUzwwyCeQ+E(M4$A)jk0lU=r z9*%z{mFtM2kh?SwEgRC%QKT~^zMy#Gr9f-P5p8^ya&&P1mF7om6lXj~}5=5=fG($Mo^U+ejXycYOkn|^CA(8+?D&uy^RNG93@Sm%{tEgMG(SO`q?V*9J)I*XB?#ZhAXD=eBPQUI zjfkeQq=ZX@AibJTMxTRa7)%aXih~(X745L@?s58DA9(0*@zOxd%b%v<=uCf?IzCay z-k(;yIn!=p#T35V2XdSG8<9IL*7xdJE!l`Ii<`^%Qr3Yj|0k1{8s;p;zA}IIX!P}2 zKmHYSr#~~29c58Vf9p5^;Zl!LYe|m0X8sqyiCp~5p1BYp@_OHmXX&&TITZWQ34DR? zDsTcITnD!?4g3zEfh2cH5dQrl^a%p|wL{lBXz5*(Vgsr_DNd;t`z6a6&w0X;Znl$+ zv92J2Z-S)r9sqiR>h2wZznP$y2~iw>iO~}6_RO~+PzR1E&=}uMUZn_|uoXrD8^c$< z!TMcwS`=&*W>rEZ9%gs0zHhu6q?lnt71%rJ9k~%Lz-)$nRP8s0RIhrf%mI+vAd%D$ zZqX(q48y_0x;y&a*m(ubqFzlFfVBOD3A;7qje8UlNTp&`lO*Jg1Q$@SJ@+h5cqB4m z8{SCHS_^DCIz#AbQkjj*+4*SIwyF0-6je_bOU^1BzgAPu2!Qj~a{S9I@KSIRr|Ss} zl7o+^SfdKHYiS#0p-5Q$f@@b7@jZ(PRNrgE*>VispGC_whE+uP!W}&Y#~~zp@1Vk% z3f*L%wd=9gnGVdpLfE8-;V}^reWE#F&eZ6;lJ;^b@aA0f(;GDlX>V&gdn+y}D}7bU z!|hG`_wPz$8O221*YJ7{S`-lBuO1zz!ngvp5OkdywNXY+HcWF}ET~8edvF<8I!d{| zKWMHgJk(1tC{<7@lBm-<1s_kIt)0tW*ZwKSel3x+nnHK`QOyQT__M_s%A;S~JWViA z=&~?}O6d!4X%^abYs=;`ezq-z+%JNB)jA&KDfsHouI8y~$Dud8Q@>(Io*-@Iv9C4y zbQ>T&gsn^Tv|OCebpI~yK8R?pCjLqFvPx`*;E7OF-qDa{xBc(8R5a2PS&H6^qfr)1 z{q7s=^v`NdOA)W4C#aeD8#smvufIm~+u={m=iu5o6M7zf{3jN!ttNXz$d^tK`vWu@wz0gLa8tn*t{)g$)+%r@M zy42A9qo=~W;k@j2!Td_mheeCU?iGvs+);HOo!phyxcZ?3+&liCKY{x``Q|jdJ;Jz5_;5p@>Vc!!mzkXhv@kb!R`&;sg`TOC-cMC= zm}W?B>f&~KRK0xoQ^F_1`iN3Cd)CVVwLcS~g7l0V5}dtIv)TTnJr>EJ*B@qvUnHEa zeB`)o%A-?ksqf|@$~Y*{SM<9q2|=HsTTjyy$1xiOQ5!Tv0-yR5JN}`v52pp*5XH-FLr})R^`>zwnfQA5YXR&K2>A36 z0cJQsDDeNV_7)4%(LUW24Tasz=G%EWr0Qd3;`5;X=nrBRGb6ysO&qXIbzH@{a%lhj zKLa{ArpMDI;@~2GO3cWB>qgFT0?g`^YO6qm2Z(j77FaB;1u0h|^uZz``}GE3JEh^2uE2>_?D;MZ?-ivRqEYrzCugD~v#;G;|y6lT0ou!}VQsw#7?pcI>xQ~+!SoM_C zd3x@1Y5mVWo+5OBu{~&a?=TOAB=9ynp$;OaQ6706E$Lj9bvKY}$^x(EObV0tR072B zxf?BIn8j$6q?)@e)OiRB5}`~8LS6R_Qn#p3$tEPar0hJ=%qTTxCa<1im0mJ7r|@)z z{+&wdox|vuKk4a$O+AKW$*7#C|1RixzZxD1T0Hq7aS%q{?+vMvV#PE_kSMgi`t<9; zY5PgUnGLB!K)_(eyt?SaV%@f<7Thq?uZfqHNt_Y#LFt6)<;(1aPwsSzS@EJPFNa>^ zw~8&CrlSS>I%g#6`p9%OT~+T@42o6@dDT4rOYLM3a23Tp?_(LHB$l9TMr#aFWHei5 zlcvg?_jF7U&uL-Ql)HN+uk01B1`lkxzz+Luq!3={?ywIV44Pc7ttFQ&y|MWOvSD>O z0fyyj=yI)l)6(z1xF}CIkiP!#(FP7&OoMus3BK)Y)S;Y3dB|(+MZ4mJ$a1ruU*c>c zXABLEajtuc>(!Jt$Yn5T6+eX~45EYw+y=toEaY6sg5b;zBo+xTO}KpH*l`p3aroA6 zsqkYo5OlI**pG(n!+PU290 z1?cY3ptb~qNKB*2V5&faC!n5O^l61=3gEK?NdmF?W6 zMBkPoCeyy-+Rxk5t_s=TM8>2dlSy_*XB#T*5 zR%+cKcDtMzQa81p?dndqp|}y$Z;wOlD?U8nKF>QhmHo{ZR$P1YYv$YdeO{jw;ZMRP z+pnFdOYLshnzaK9s@?9q5p=ZGT_24OUiq~6EKj#sUdehE^71_o4v{#Yn{>*TN>Vg7 z7k5%MP8yh@N(S@t@tQ$%m^$PKHpSB@keN#YA-~x*S6kgBr9TlLOPaSE>o^xW{NyXgHwc`4>Z8oAY$gQniQl@zJ|4<5 z;?tyJuwki>MyP>9d18A_K{7luJa6EpTMfVxda#*vMBReHxSiU71O3%~_L4><$Z_wM z69MC}ntMd?Ecl;;=;ch(lT!*N()o-5VC7k3Bv637pvId58>+RaQQ(!Zd{`JbI$}~w zyPND^SzGLv0!WxcU0EDajj7=ijf_r6oJ+Iam0p%R$qAEFkj|q%6Nj}Kh)hHhN6JaM zLR$$4=|4#+MxHJ=FtJ#r&(`jy%Ef`;>s0^^j-<|GV!;0@FYupgg4A6e6^!pCA|oKc zL;cES77u&}F`F(agT^J8Gu%+NsZI4l2FXezB1SfrCof$z442_nj4y|M7p!tN^D(QA zW{zvzq$<)sx-{=K@T(iW_kPTSRnEt~5O$7!i}!xM1RK!fe-yHkPc~##^46x12teMm z;LahNvf}e`kKThlSLH68YbUF&Qey7(KrsBAUVXmV&`u7qB;-aAIBG_PDtO3oF%XA$ zdQYWC6nui%*cgOFaViY|x~ZE3;>%1Mo#_(IbBC!{fM6(`_>>OVo zdr9ZGQa3HMyb7to)vzbjB~}{T7!#cxC7v}_THUL*s4gokN|@~xbco(8<*ab-7Rl%y zCOSD{58{aF{92eRlsvCbQzA+dF{@|D9VMeg=}Kc?UdA}fWcX#Hxdh&WeoBsjhedyh zH8V-n39@Xe@Y#uLe(KY@ZIYk!772(%@KC)-d_3XlAtBIRP4YQya*5g7I4|yQsA|O~yJ8Ys6IVj&k2}+n)Vz8?0QipYNEr1?h z#X98wLj6d=L%ADnjA|r3jdR^+kGkIh>^2(O?F$iK@ToDyB&aQjCK@+1cAVTs`HB00 zswSu|p}_D85Nd`8UQGo+r4!dpj?PsD+ixav7U1SG>+l{0xrtz8QaW78Kp3xu< zHPcfLXh6^=a8P)Q;Qr75!TB{mYiM?<1$N$*xL6G+FV+Wt4`ykb877h-Og_w`pz*U-<9 zf)JkxXKj*lwfY}agu2m$eVYx=+J%xG0Jb=PUk5x|en&IT5NE3$Yg=Y+vGoIH^m3*C zK{;26HdIQ;$v5VY-MC6xpt>gh)CMgkk@?I;D_u>@MZ*^B?`XRGm!p~*8Hb)q{yVrk zQkHP7A_qOKw?DtnQ@Hu!u)cy2W7IEd9dn7Pnz!Bv|7 E55%4tQUCw| literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr.meta new file mode 100644 index 0000000..c67c654 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: 865812f5b782c4748867c275df258bfc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 1 + seamlessCubemap: 1 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 0 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 2 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 100 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsOnline/ReflectionProbe-0.exr + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity new file mode 100644 index 0000000..e2a6ffa --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity @@ -0,0 +1,1042 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.048727296, g: 0.049995184, b: 0.14150941, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 2100000, guid: 81f714daf7144784b8a2f42f1cd30927, type: 2} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.2328035, g: 0.23442134, b: 0.27287462, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000006, guid: 71d66be797c1eb44bab0797662b33cbc, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &126437272 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 126437274} + - component: {fileID: 126437273} + m_Layer: 0 + m_Name: Environment + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &126437273 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 126437272} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 1317994002 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!4 &126437274 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 126437272} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1373387508} + - {fileID: 1445828407} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &472411619 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 472411620} + - component: {fileID: 472411621} + m_Layer: 0 + m_Name: StartPosition + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &472411620 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 472411619} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -6, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1518259679} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &472411621 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 472411619} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &493146027 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 493146028} + - component: {fileID: 493146029} + m_Layer: 0 + m_Name: StartPosition + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &493146028 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 493146027} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -9, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1518259679} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &493146029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 493146027} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &939597736 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 939597737} + m_Layer: 0 + m_Name: Cubes + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &939597737 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 939597736} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3181899219847070119} + - {fileID: 1294796099} + - {fileID: 2120764046} + - {fileID: 1071886464} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1071886463 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 939597737} + m_Modifications: + - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: sceneId + value: 656062201 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.x + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} +--- !u!4 &1071886464 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + m_PrefabInstance: {fileID: 1071886463} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1224119056 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1224119057} + - component: {fileID: 1224119058} + m_Layer: 0 + m_Name: StartPosition + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1224119057 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1224119056} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1518259679} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1224119058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1224119056} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1294796098 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 939597737} + m_Modifications: + - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: sceneId + value: 3113436280 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.x + value: -1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} +--- !u!4 &1294796099 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + m_PrefabInstance: {fileID: 1294796098} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1333422873 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_Name + value: PhysicsSimulator + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 99d75386017b4ba44ad1482ee7938f5a, type: 3} +--- !u!4 &1373387508 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + m_PrefabInstance: {fileID: 7582855648999245619} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1445828406 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 126437274} + m_Modifications: + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008055, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_Name + value: Plane + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, type: 3} +--- !u!4 &1445828407 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + m_PrefabInstance: {fileID: 1445828406} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1513281386 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1513281387} + - component: {fileID: 1513281388} + m_Layer: 0 + m_Name: StartPosition + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1513281387 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1513281386} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1518259679} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1513281388 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1513281386} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1518259678 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1518259679} + m_Layer: 0 + m_Name: StartPosttions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1518259679 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1518259678} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 493146028} + - {fileID: 472411620} + - {fileID: 1513281387} + - {fileID: 1224119057} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &2120764045 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 939597737} + m_Modifications: + - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: sceneId + value: 3424948259 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.x + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} +--- !u!4 &2120764046 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + m_PrefabInstance: {fileID: 2120764045} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1098173225757504847 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.x + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.z + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622925, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_Name + value: Portal + objectReference: {fileID: 0} + - target: {fileID: 3141292696673982546, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: sceneId + value: 182638750 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: startPosition.x + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: startPosition.z + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: destinationScene + value: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: c624c75494b4d7d4086b9212f897e56a, type: 3} +--- !u!1001 &3181899219847070118 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 939597737} + m_Modifications: + - target: {fileID: -1828993248307539358, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: sceneId + value: 3043478025 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528418, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.x + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 7c6a0a278eba11e44b9a86cd4da603df, type: 3} +--- !u!4 &3181899219847070119 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 3181899219042528419, guid: 7c6a0a278eba11e44b9a86cd4da603df, + type: 3} + m_PrefabInstance: {fileID: 3181899219847070118} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7582855648999245619 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 126437274} + m_Modifications: + - target: {fileID: 7582855647636897216, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_Name + value: StartPoint + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.x + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.z + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 849c125c9d8094249b3c664da1cd143a, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity.meta new file mode 100644 index 0000000..be18974 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 91c0fa5f4542be14dbad5c838292056b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity new file mode 100644 index 0000000..f9e7a75 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity @@ -0,0 +1,841 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.048727296, g: 0.049995184, b: 0.14150941, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 2100000, guid: 81f714daf7144784b8a2f42f1cd30927, type: 2} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.2328035, g: 0.23442134, b: 0.27287462, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000004, guid: 71d66be797c1eb44bab0797662b33cbc, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1001 &571924470 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.x + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalPosition.z + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622921, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1098173225717622925, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: m_Name + value: Portal + objectReference: {fileID: 0} + - target: {fileID: 3141292696673982546, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: sceneId + value: 1073849646 + objectReference: {fileID: 0} + - target: {fileID: 3141292696673982546, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: serverOnly + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: startPosition.x + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: startPosition.z + value: -10 + objectReference: {fileID: 0} + - target: {fileID: 5948271423698091598, guid: c624c75494b4d7d4086b9212f897e56a, + type: 3} + propertyPath: destinationScene + value: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel1.unity + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: c624c75494b4d7d4086b9212f897e56a, type: 3} +--- !u!1001 &1071886463 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1514693545} + m_Modifications: + - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: sceneId + value: 2068572849 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.x + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} +--- !u!4 &1071886464 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + m_PrefabInstance: {fileID: 1071886463} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1294796098 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1514693545} + m_Modifications: + - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: sceneId + value: 131067959 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.x + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} +--- !u!4 &1294796099 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + m_PrefabInstance: {fileID: 1294796098} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1333422873 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_Name + value: PhysicsSimulator + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 99d75386017b4ba44ad1482ee7938f5a, type: 3} +--- !u!1 &1514693544 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1514693545} + m_Layer: 0 + m_Name: Spheres + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1514693545 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1514693544} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2188792038635513490} + - {fileID: 1294796099} + - {fileID: 2120764046} + - {fileID: 1071886464} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1932534637 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1932534639} + - component: {fileID: 1932534638} + m_Layer: 0 + m_Name: Environment + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1932534638 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1932534637} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 159404139 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!4 &1932534639 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1932534637} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6358973573665600640} + - {fileID: 1999985658} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1999985657 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1932534639} + m_Modifications: + - target: {fileID: 7582855647636897216, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_Name + value: StartPoint + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.x + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalPosition.z + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 849c125c9d8094249b3c664da1cd143a, type: 3} +--- !u!4 &1999985658 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7582855647636897223, guid: 849c125c9d8094249b3c664da1cd143a, + type: 3} + m_PrefabInstance: {fileID: 1999985657} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2120764045 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1514693545} + m_Modifications: + - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: sceneId + value: 1581864539 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} +--- !u!4 &2120764046 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + m_PrefabInstance: {fileID: 2120764045} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2188792038635513489 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1514693545} + m_Modifications: + - target: {fileID: -5172514306435102607, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: sceneId + value: 3873206969 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.x + value: -7 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2188792038427236743, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e588080aa542be54d9ca9d5c734dc9ee, type: 3} +--- !u!4 &2188792038635513490 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2188792038427236742, guid: e588080aa542be54d9ca9d5c734dc9ee, + type: 3} + m_PrefabInstance: {fileID: 2188792038635513489} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &6358973573665600639 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1932534639} + m_Modifications: + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7349408984269008055, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + propertyPath: m_Name + value: Plane + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, type: 3} +--- !u!4 &6358973573665600640 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7349408984269008052, guid: 4fdcc4aa5c669b348a5954a92f5e8e89, + type: 3} + m_PrefabInstance: {fileID: 6358973573665600639} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity.meta b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity.meta new file mode 100644 index 0000000..ed23667 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e8e2dc8c3ef824b468c6f6e1980a4b27 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scenes/MirrorAdditiveLevelsSubLevel2.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta new file mode 100644 index 0000000..4e40c32 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: daf19edd647d8ae4ead9cb46f24f5424 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs new file mode 100644 index 0000000..3309a88 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs @@ -0,0 +1,187 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.AdditiveLevels +{ + [AddComponentMenu("")] + public class AdditiveLevelsNetworkManager : NetworkManager + { + public static new AdditiveLevelsNetworkManager singleton => (AdditiveLevelsNetworkManager)NetworkManager.singleton; + + [Header("Additive Scenes - First is start scene")] + + [Scene, Tooltip("Add additive scenes here.\nFirst entry will be players' start scene")] + public string[] additiveScenes; + + [Header("Fade Control - See child FadeCanvas")] + + [Tooltip("Reference to FadeInOut script on child FadeCanvas")] + public FadeInOut fadeInOut; + + // This is set true after server loads all subscene instances + bool subscenesLoaded; + + // This is managed in LoadAdditive, UnloadAdditive, and checked in OnClientSceneChanged + bool isInTransition; + + #region Scene Management + + ///

+ /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). + /// + /// The name of the new scene. + public override void OnServerSceneChanged(string sceneName) + { + // This fires after server fully changes scenes, e.g. offline to online + // If server has just loaded the Container (online) scene, load the subscenes on server + if (sceneName == onlineScene) + StartCoroutine(ServerLoadSubScenes()); + } + + IEnumerator ServerLoadSubScenes() + { + foreach (string additiveScene in additiveScenes) + yield return SceneManager.LoadSceneAsync(additiveScene, new LoadSceneParameters + { + loadSceneMode = LoadSceneMode.Additive, + localPhysicsMode = LocalPhysicsMode.Physics3D // change this to .Physics2D for a 2D game + }); + + subscenesLoaded = true; + } + + /// + /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed + /// This allows client to do work / cleanup / prep before the scene changes. + /// + /// Name of the scene that's about to be loaded + /// Scene operation that's about to happen + /// true to indicate that scene loading will be handled through overrides + public override void OnClientChangeScene(string sceneName, SceneOperation sceneOperation, bool customHandling) + { + //Debug.Log($"{System.DateTime.Now:HH:mm:ss:fff} OnClientChangeScene {sceneName} {sceneOperation}"); + + if (sceneOperation == SceneOperation.UnloadAdditive) + StartCoroutine(UnloadAdditive(sceneName)); + + if (sceneOperation == SceneOperation.LoadAdditive) + StartCoroutine(LoadAdditive(sceneName)); + } + + IEnumerator LoadAdditive(string sceneName) + { + isInTransition = true; + + // This will return immediately if already faded in + // e.g. by UnloadAdditive or by default startup state + yield return fadeInOut.FadeIn(); + + // host client is on server...don't load the additive scene again + if (mode == NetworkManagerMode.ClientOnly) + { + // Start loading the additive subscene + loadingSceneAsync = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); + + while (loadingSceneAsync != null && !loadingSceneAsync.isDone) + yield return null; + } + + // Reset these to false when ready to proceed + NetworkClient.isLoadingScene = false; + isInTransition = false; + + OnClientSceneChanged(); + + // Reveal the new scene content. + yield return fadeInOut.FadeOut(); + } + + IEnumerator UnloadAdditive(string sceneName) + { + isInTransition = true; + + // This will return immediately if already faded in + // e.g. by LoadAdditive above or by default startup state. + yield return fadeInOut.FadeIn(); + + // host client is on server...don't unload the additive scene here. + if (mode == NetworkManagerMode.ClientOnly) + { + yield return SceneManager.UnloadSceneAsync(sceneName); + yield return Resources.UnloadUnusedAssets(); + } + + // Reset these to false when ready to proceed + NetworkClient.isLoadingScene = false; + isInTransition = false; + + OnClientSceneChanged(); + + // There is no call to FadeOut here on purpose. + // Expectation is that a LoadAdditive or full scene change + // will follow that will call FadeOut after that scene loads. + } + + /// + /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. + /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. + /// + /// The network connection that the scene change message arrived on. + public override void OnClientSceneChanged() + { + // Only call the base method if not in a transition. + // This will be called from LoadAdditive / UnloadAdditive after setting isInTransition to false + // but will also be called first by Mirror when the scene loading finishes. + if (!isInTransition) + base.OnClientSceneChanged(); + } + + #endregion + + #region Server System Callbacks + + /// + /// Called on the server when a client is ready. + /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. + /// + /// Connection from client. + public override void OnServerReady(NetworkConnectionToClient conn) + { + // This fires from a Ready message client sends to server after loading the online scene + base.OnServerReady(conn); + + if (conn.identity == null) + StartCoroutine(AddPlayerDelayed(conn)); + } + + // This delay is mostly for the host player that loads too fast for the + // server to have subscenes async loaded from OnServerSceneChanged ahead of it. + IEnumerator AddPlayerDelayed(NetworkConnectionToClient conn) + { + // Wait for server to async load all subscenes for game instances + while (!subscenesLoaded) + yield return null; + + // Send Scene msg to client telling it to load the first additive scene + conn.Send(new SceneMessage { sceneName = additiveScenes[0], sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); + + // We have Network Start Positions in first additive scene...pick one + Transform start = GetStartPosition(); + + // Instantiate player as child of start position - this will place it in the additive scene + // This also lets player object "inherit" pos and rot from start position transform + GameObject player = Instantiate(playerPrefab, start); + // now set parent null to get it out from under the Start Position object + player.transform.SetParent(null); + + // Wait for end of frame before adding the player to ensure Scene Message goes first + yield return new WaitForEndOfFrame(); + + // Finally spawn the player object for this connection + NetworkServer.AddPlayerForConnection(conn, player); + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta new file mode 100644 index 0000000..e12a827 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 01eafa8309a0894479f0f87ae1a9c30f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scripts/AdditiveLevelsNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs new file mode 100644 index 0000000..6dcad3b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs @@ -0,0 +1,77 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.AdditiveLevels +{ + public class FadeInOut : MonoBehaviour + { + [Header("Components")] + [SerializeField] Image panelImage; + + [Header("Settings")] + [SerializeField, Range(1, 10)] + [Tooltip("Time in seconds to fade in")] + byte fadeInTime = 2; + + [SerializeField, Range(1, 10)] + [Tooltip("Time in seconds to fade out")] + byte fadeOutTime = 2; + + bool isFading; + + void OnValidate() + { + if (panelImage == null) + panelImage = GetComponentInChildren(); + + fadeInTime = (byte)Mathf.Max(fadeInTime, 1); + fadeOutTime = (byte)Mathf.Max(fadeOutTime, 1); + } + + public float GetFadeInTime() => fadeInTime + Time.fixedDeltaTime; + + public IEnumerator FadeIn() + { + //Debug.Log($"FadeIn {isFading}"); + yield return FadeImage(0f, 1f, fadeInTime); + } + + public float GetFadeOutTime() => fadeOutTime + Time.fixedDeltaTime; + + public IEnumerator FadeOut() + { + //Debug.Log($"FadeOut {isFading}"); + yield return FadeImage(1f, 0f, fadeOutTime); + } + + private IEnumerator FadeImage(float startAlpha, float endAlpha, float duration) + { + if (panelImage == null) yield break; + + if (isFading) yield break; + + // Short circuit if the alpha is already at endAlpha + Color color = panelImage.color; + if (Mathf.Approximately(color.a, endAlpha)) yield break; + + isFading = true; + + float elapsedTime = 0f; + float fixedDeltaTime = Time.fixedDeltaTime; + + while (elapsedTime < duration) + { + elapsedTime += fixedDeltaTime; + float alpha = Mathf.Lerp(startAlpha, endAlpha, elapsedTime / duration); + panelImage.color = new Color(color.r, color.g, color.b, alpha); + yield return new WaitForFixedUpdate(); + } + + // Ensure the final alpha value is set + panelImage.color = new Color(color.r, color.g, color.b, endAlpha); + + isFading = false; + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta new file mode 100644 index 0000000..0e0091b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 363a8867bb9c7b845a73233566df8c1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scripts/FadeInOut.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs new file mode 100644 index 0000000..ccb88fb --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +namespace Mirror.Examples.AdditiveLevels +{ + // This script is attached to portal labels to keep them facing the camera + public class LookAtMainCamera : MonoBehaviour + { + // This will be enabled by Portal script in OnStartClient + void OnValidate() + { + this.enabled = false; + } + + // LateUpdate so that all camera updates are finished. + [ClientCallback] + void LateUpdate() + { + transform.forward = Camera.main.transform.forward; + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta new file mode 100644 index 0000000..3e2f284 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: cc58300ee45438a418d9e32957fdc0c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scripts/LookAtMainCamera.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs new file mode 100644 index 0000000..2a73c42 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs @@ -0,0 +1,104 @@ +using System.Collections; +using System.IO; +using System.Text.RegularExpressions; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.AdditiveLevels +{ + public class Portal : NetworkBehaviour + { + [Scene, Tooltip("Which scene to send player from here")] + public string destinationScene; + + [Tooltip("Where to spawn player in Destination Scene")] + public Vector3 startPosition; + + [Tooltip("Reference to child TextMesh label")] + public TextMesh label; // don't depend on TMPro. 2019 errors. + + [SyncVar(hook = nameof(OnLabelTextChanged))] + public string labelText; + + public void OnLabelTextChanged(string _, string newValue) + { + label.text = labelText; + } + + public override void OnStartServer() + { + labelText = Path.GetFileNameWithoutExtension(destinationScene).Replace("MirrorAdditiveLevels", ""); + + // Simple Regex to insert spaces before capitals, numbers + labelText = Regex.Replace(labelText, @"\B[A-Z0-9]+", " $0"); + } + + public override void OnStartClient() + { + if (label.TryGetComponent(out LookAtMainCamera lookAtMainCamera)) + lookAtMainCamera.enabled = true; + } + + // Note that I have created layers called Player(6) and Portal(7) and set them + // up in the Physics collision matrix so only Player collides with Portal. + void OnTriggerEnter(Collider other) + { + if (!(other is CapsuleCollider)) return; // ignore CharacterController colliders + + //Debug.Log($"Portal.OnTriggerEnter {other}"); + // tag check in case you didn't set up the layers and matrix as noted above + if (!other.CompareTag("Player")) return; + + // applies to host client on server and remote clients + if (other.TryGetComponent(out Common.Controllers.Player.PlayerControllerBase playerController)) + playerController.enabled = false; + + if (isServer) + StartCoroutine(SendPlayerToNewScene(other.gameObject)); + } + + [ServerCallback] + IEnumerator SendPlayerToNewScene(GameObject player) + { + if (!player.TryGetComponent(out NetworkIdentity identity)) yield break; + + NetworkConnectionToClient conn = identity.connectionToClient; + if (conn == null) yield break; + + // Tell client to unload previous subscene with custom handling (see NetworkManager::OnClientChangeScene). + conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true }); + + // wait for fader to complete. + yield return new WaitForSeconds(AdditiveLevelsNetworkManager.singleton.fadeInOut.GetFadeInTime()); + + // Remove player after fader has completed + NetworkServer.RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn); + + // yield a frame allowing interest management to update + // and all spawned objects to be destroyed on client + yield return null; + + // reposition player on server and client + player.transform.position = startPosition; + + // Rotate player to face center of scene + // Player is 2m tall with pivot at 0,1,0 so we need to look at + // 1m height to not tilt the player down to look at origin + player.transform.LookAt(Vector3.up); + + // Move player to new subscene. + SceneManager.MoveGameObjectToScene(player, SceneManager.GetSceneByPath(destinationScene)); + + // Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene). + conn.Send(new SceneMessage { sceneName = destinationScene, sceneOperation = SceneOperation.LoadAdditive, customHandling = true }); + + // Player will be spawned after destination scene is loaded + NetworkServer.AddPlayerForConnection(conn, player); + + // host client playerController would have been disabled by OnTriggerEnter above + // Remote client players are respawned with playerController already enabled + if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent(out Common.Controllers.Player.PlayerControllerBase playerController)) + playerController.enabled = true; + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta new file mode 100644 index 0000000..24eab4b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0e680878006965146a8f9d85834c4d1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Scripts/Portal.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures.meta new file mode 100644 index 0000000..9335d0d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Textures.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a1ac2873c4eb8d64db33d7df8acb9188 +folderAsset: yes +timeCreated: 1497127550 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Back_Tex.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f5d4c11bf1076159b76e975884ef051a67ea76f6 GIT binary patch literal 68766 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta new file mode 100644 index 0000000..5cc3a19 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: 9ffeeee1accdc4b4faf2b3e27b226340 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Textures/Down_Tex.jpeg + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5e91f3f23b0d1583f50cf4268a7c71ce0a3978c0 GIT binary patch literal 72964 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta b/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta new file mode 100644 index 0000000..88369b8 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: ca928ef0e269448ba82388eb41d48544 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveLevels/Textures/Front_Tex.jpeg + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg b/Assets/Mirror/Examples/AdditiveLevels/Textures/Left_Tex.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5f7de24d423d12697a8d207d36ad986479daad53 GIT binary patch literal 68026 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

+>rMOvL;uV}qp-&>li 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

(iYbRfbpta)i7 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 ImBxSn*> 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%0D_2!&w$???@3A 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 Build and Run + +Start up to 3 built instances: These will all be client players. + +Press Play in the Editor and click Host (Server + Client) in the HUD +- This will be the host and the 1st player of up to 4. You can also use Server Only if you prefer. + +Click Client in the built instances. +- WASDQE keys to move & turn your player capsule. +- There are objects in the corners of the scene hidden by Proximity Checkers. +- The big area in the middle is where the subscene will be loaded when you get near the shelter. +- There are also networked objects inside the subscene, also with Proximity Checkers. +- Since subscenes are only loaded for individual clients, other clients that are outside the middle Zone won't see what those in the subscene can see. +- If you play a built instance as Host or Server and play as client in the editor, you'll see the subscene content load and unload in the hierarchy as you move in and out of the middle Zone. diff --git a/Assets/Mirror/Examples/AdditiveScenes/README.md.meta b/Assets/Mirror/Examples/AdditiveScenes/README.md.meta new file mode 100644 index 0000000..a2be82d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0a023e0d7315ac74094703ab69348733 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/README.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta new file mode 100644 index 0000000..79b44f1 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e989860f377e7764bb7787086ef44ea4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.meta new file mode 100644 index 0000000..30e09f8 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2ffed76314eba649951a5b2c1dbb427 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity new file mode 100644 index 0000000..6c67317 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity @@ -0,0 +1,2167 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 1405375879} + m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 10 + m_AtlasSize: 512 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 0 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 256 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000004, guid: df141818507db234cb3ca8bf3ab28a3f, + type: 2} + m_UseShadowmask: 0 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &34755345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 34755346} + - component: {fileID: 34755348} + - component: {fileID: 34755347} + m_Layer: 0 + m_Name: VisibleRangeCapsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &34755346 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_LocalRotation: {x: 0, y: 0.3826836, z: -0, w: -0.92387944} + m_LocalPosition: {x: 20, y: 1, z: -20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 315, z: 0} +--- !u!23 &34755347 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &34755348 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34755345} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &47225730 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 47225731} + m_Layer: 0 + m_Name: ProximityVisualizers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &47225731 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 47225730} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1727677799} + - {fileID: 62078680} + - {fileID: 589935541} + - {fileID: 34755346} + m_Father: {fileID: 909502395} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &62078679 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 62078680} + - component: {fileID: 62078682} + - component: {fileID: 62078681} + m_Layer: 0 + m_Name: VisibleRangeCylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &62078680 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_LocalRotation: {x: 0, y: 0.9238796, z: -0, w: -0.38268325} + m_LocalPosition: {x: 20, y: 1, z: 20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 225, z: 0} +--- !u!23 &62078681 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &62078682 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62078679} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &160176455 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.x + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalPosition.z + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.w + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.y + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 45 + objectReference: {fileID: 0} + - target: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 160176457, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: m_Name + value: Tank + objectReference: {fileID: 0} + - target: {fileID: 160176459, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} + propertyPath: sceneId + value: 1758079699 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ab222ed73ada1ac4ba2f61e843d7627c, type: 3} +--- !u!4 &160176456 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 160176456, guid: ab222ed73ada1ac4ba2f61e843d7627c, + type: 3} + m_PrefabInstance: {fileID: 160176455} + m_PrefabAsset: {fileID: 0} +--- !u!1 &178547537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 178547538} + - component: {fileID: 178547539} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &178547538 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178547537} + m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} + m_LocalPosition: {x: 0, y: 1.02, z: 20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!114 &178547539 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 178547537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &534669902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 534669905} + - component: {fileID: 534669904} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &534669904 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 40 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &534669905 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 70, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &589935540 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 589935541} + - component: {fileID: 589935543} + - component: {fileID: 589935542} + m_Layer: 0 + m_Name: VisibleRangeTank + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &589935541 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: -20, y: 1, z: -20} + m_LocalScale: {x: 20, y: 20, z: 20} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0} +--- !u!23 &589935542 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &589935543 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589935540} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &612284967 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 612284968} + - component: {fileID: 612284971} + - component: {fileID: 612284970} + - component: {fileID: 612284969} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &612284968 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 8, y: 3, z: -8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &612284969 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &612284970 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &612284971 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612284967} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &652875644 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 652875645} + - component: {fileID: 652875646} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &652875645 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 652875644} + m_LocalRotation: {x: 0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 20, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 270, z: 0} +--- !u!114 &652875646 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 652875644} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &691846569 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 691846570} + - component: {fileID: 691846571} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &691846570 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691846569} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.02, z: -20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &691846571 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 691846569} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &748207074 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 855244094988030905, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.x + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.z + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 135 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: sceneId + value: 744240842 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_AssetId + value: f6d08eb9a8e35d84fa30a7e3ae64181a + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_SceneId + value: 529586728 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, type: 3} +--- !u!4 &748207075 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + m_PrefabInstance: {fileID: 748207074} + m_PrefabAsset: {fileID: 0} +--- !u!1 &794922164 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 794922165} + - component: {fileID: 794922168} + - component: {fileID: 794922167} + - component: {fileID: 794922166} + m_Layer: 0 + m_Name: Roof + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &794922165 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 6, z: 0} + m_LocalScale: {x: 20, y: 0.2, z: 20} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &794922166 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 2, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &794922167 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &794922168 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 794922164} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &856402103 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 856402104} + - component: {fileID: 856402107} + - component: {fileID: 856402106} + - component: {fileID: 856402105} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &856402104 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -8, y: 3, z: 8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &856402105 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &856402106 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &856402107 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 856402103} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &901271862 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 6852530814182375312, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_Name + value: Cylinder + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.x + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.z + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.38268325 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.9238796 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 225 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: sceneId + value: 4277306991 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_SceneId + value: 568164022 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 12a4c14e672c00b4b840f937d824b890, type: 3} +--- !u!4 &901271863 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + m_PrefabInstance: {fileID: 901271862} + m_PrefabAsset: {fileID: 0} +--- !u!1 &909502394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 909502395} + m_Layer: 0 + m_Name: Prefabs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &909502395 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 909502394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 748207075} + - {fileID: 901271863} + - {fileID: 160176456} + - {fileID: 1284471874} + - {fileID: 47225731} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1047741290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1047741291} + - component: {fileID: 1047741294} + - component: {fileID: 1047741293} + - component: {fileID: 1047741292} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1047741291 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -8, y: 3, z: -8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1047741292 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1047741293 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1047741294 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047741290} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1131499124 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1131499132} + - component: {fileID: 1131499131} + - component: {fileID: 1131499130} + - component: {fileID: 1131499129} + - component: {fileID: 1131499128} + - component: {fileID: 1131499127} + - component: {fileID: 1131499126} + - component: {fileID: 1131499125} + m_Layer: 0 + m_Name: PlayArea + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &1131499125 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: 5} +--- !u!65 &1131499126 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: -5} +--- !u!65 &1131499127 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: 5, y: 4, z: 0} +--- !u!65 &1131499128 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: -5, y: 4, z: 0} +--- !u!64 &1131499129 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1131499130 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6eb3f3ba66756364d8b94e662e7e8af5, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1131499131 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1131499132 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1131499124} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 5, y: 1, z: 5} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1172568541 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1172568542} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1172568542 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1172568541} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 178547538} + - {fileID: 1816951100} + - {fileID: 652875645} + - {fileID: 691846570} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &1284471874 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + m_PrefabInstance: {fileID: 1076878375580925077} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1405375878 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1405375880} + - component: {fileID: 1405375879} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1405375879 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1405375878} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.9622642, g: 0.90969414, b: 0.748932, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1405375880 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1405375878} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &1462312433 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1462312434} + - component: {fileID: 1462312437} + - component: {fileID: 1462312436} + - component: {fileID: 1462312435} + m_Layer: 0 + m_Name: Pillar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1462312434 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 8, y: 3, z: 8} + m_LocalScale: {x: 1, y: 3, z: 1} + m_Children: [] + m_Father: {fileID: 1608696205} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!136 &1462312435 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5000001 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697} +--- !u!23 &1462312436 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: aef230244d219314fb8453f0365b8176, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1462312437 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462312433} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1471959939 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1471959942} + - component: {fileID: 1471959941} + - component: {fileID: 1471959940} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1471959940 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1471959939} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1471959941 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1471959939} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1471959942 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1471959939} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1608696204 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1608696205} + m_Layer: 0 + m_Name: Shelter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1608696205 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1608696204} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1047741291} + - {fileID: 612284968} + - {fileID: 1462312434} + - {fileID: 856402104} + - {fileID: 794922165} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1630383476 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1630383479} + - component: {fileID: 1630383478} + - component: {fileID: 1630383477} + m_Layer: 0 + m_Name: ZoneVisualizer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1630383477 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1630383478 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1630383479 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1630383476} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 32, y: 32, z: 32} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1661834277 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1661834279} + - component: {fileID: 1661834281} + - component: {fileID: 1661834278} + - component: {fileID: 1661834280} + - component: {fileID: 1661834282} + - component: {fileID: 1661834283} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!114 &1661834278 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 34d1daf9e7dbcb64aa647cb332054ea6, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1661834280} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 8872462076811691049, guid: a5bdca0a2315d43499be7dcef473fbc7, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + Zone: {fileID: 3460729395543957449, guid: de939020b5e2aa5489ebcc4002d75d54, type: 3} + subScenes: + - Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity +--- !u!4 &1661834279 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1661834280 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1661834281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1661834282 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8f60becab051427fbdd3c8ac9ab4712b, type: 3} + m_Name: + m_EditorClassIdentifier: + visRange: 5 + rebuildInterval: 0.1 +--- !u!114 &1661834283 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1661834277} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1 &1727677796 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1727677799} + - component: {fileID: 1727677798} + - component: {fileID: 1727677797} + m_Layer: 0 + m_Name: VisibleRangeSphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1727677797 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1727677798 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1727677799 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1727677796} + m_LocalRotation: {x: 0, y: 0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: -20, y: 1, z: 20} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 47225731} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 135, z: 0} +--- !u!1 &1816951099 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1816951100} + - component: {fileID: 1816951101} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1816951100 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1816951099} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -20, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1172568542} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!114 &1816951101 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1816951099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &1076878375580925077 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 909502395} + m_Modifications: + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_Name + value: Capsule + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.x + value: 20 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.z + value: -20 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.92387944 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.3826836 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 315 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: sceneId + value: 2757245015 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_SceneId + value: 2061538488 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e1971f4a8c7661546bc509b44bd91b80, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity.meta new file mode 100644 index 0000000..4a99e8d --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7a0eee2f518e9dc4fb628d96dc452faf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/LightingData.asset b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/LightingData.asset new file mode 100644 index 0000000000000000000000000000000000000000..4c63479c2949354ec0f251f0d6b0274ba5dd8a23 GIT binary patch literal 19240 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr.meta new file mode 100644 index 0000000..e791b24 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: 9cb9c1b35983e37428ad64fd87a8c975 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 1 + seamlessCubemap: 1 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 0 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 2 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 100 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesMain/ReflectionProbe-0.exr + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity new file mode 100644 index 0000000..0fe1b53 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity @@ -0,0 +1,840 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000002, guid: df141818507db234cb3ca8bf3ab28a3f, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &21610633 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 21610634} + - component: {fileID: 21610636} + - component: {fileID: 21610635} + m_Layer: 0 + m_Name: VisibleRangeCapsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &21610634 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_LocalRotation: {x: 0, y: 0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: 3, y: 1, z: -3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 135, z: 0} +--- !u!23 &21610635 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &21610636 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 21610633} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &174598777 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_Name + value: Capsule + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499732, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.x + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalPosition.z + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 135 + objectReference: {fileID: 0} + - target: {fileID: 1076878374699499735, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: sceneId + value: 3231330715 + objectReference: {fileID: 0} + - target: {fileID: 2648107611936813301, guid: e1971f4a8c7661546bc509b44bd91b80, + type: 3} + propertyPath: m_SceneId + value: 15452677 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e1971f4a8c7661546bc509b44bd91b80, type: 3} +--- !u!1 &222935521 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 222935522} + - component: {fileID: 222935524} + - component: {fileID: 222935523} + m_Layer: 0 + m_Name: VisibleRangeSphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &222935522 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_LocalRotation: {x: 0, y: 0.3826836, z: -0, w: -0.92387944} + m_LocalPosition: {x: -3, y: 1, z: 3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 315, z: 0} +--- !u!23 &222935523 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &222935524 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 222935521} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &507729669 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 507729670} + - component: {fileID: 507729672} + - component: {fileID: 507729671} + m_Layer: 0 + m_Name: VisibleRangeCylinder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &507729670 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: 3, y: 1, z: 3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0} +--- !u!23 &507729671 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &507729672 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507729669} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1690140970 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1690140971} + m_Layer: 0 + m_Name: ProximityVisualizers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1690140971 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1690140970} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1722279649} + - {fileID: 21610634} + - {fileID: 222935522} + - {fileID: 507729670} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1722279648 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1722279649} + - component: {fileID: 1722279651} + - component: {fileID: 1722279650} + m_Layer: 0 + m_Name: VisibleRangeCube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1722279649 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_LocalRotation: {x: 0, y: 0.9238796, z: -0, w: -0.38268325} + m_LocalPosition: {x: -3, y: 1, z: -3} + m_LocalScale: {x: 10, y: 10, z: 10} + m_Children: [] + m_Father: {fileID: 1690140971} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 225, z: 0} +--- !u!23 &1722279650 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a7c679cf124f7ae46a0291ea35848554, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1722279651 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1722279648} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1001 &855244095324068329 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 855244094988030905, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_Name + value: Sphere + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.x + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalPosition.z + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.92387944 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.3826836 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 315 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030909, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: sceneId + value: 1396685688 + objectReference: {fileID: 0} + - target: {fileID: 855244094988030911, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_SceneId + value: 11893259 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_CastShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_ReceiveShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 855244096231524078, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, + type: 3} + propertyPath: m_ReflectionProbeUsage + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: f6d08eb9a8e35d84fa30a7e3ae64181a, type: 3} +--- !u!1001 &5623359707641229621 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_CastShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_ReceiveShadows + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359706949397433, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_ReflectionProbeUsage + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648404, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: sceneId + value: 86995073 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648404, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_SceneId + value: 4733130 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.x + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalPosition.z + value: -3 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.w + value: -0.38268325 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.9238796 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 225 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648426, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_Icon + value: + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_Name + value: Cube + objectReference: {fileID: 0} + - target: {fileID: 5623359707189648430, guid: 4ff300cf6bb3c6342a9552c4f18788c8, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 4ff300cf6bb3c6342a9552c4f18788c8, type: 3} +--- !u!1001 &6852530815080958608 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6852530814182375312, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_Name + value: Cylinder + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.x + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalPosition.z + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.92387956 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.y + value: 0.38268343 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 45 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375316, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: sceneId + value: 3262924414 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_AssetId + value: 12a4c14e672c00b4b840f937d824b890 + objectReference: {fileID: 0} + - target: {fileID: 6852530814182375318, guid: 12a4c14e672c00b4b840f937d824b890, + type: 3} + propertyPath: m_SceneId + value: 4633990 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 12a4c14e672c00b4b840f937d824b890, type: 3} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity.meta b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity.meta new file mode 100644 index 0000000..c7b8811 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7f4fd683fc6d866418c95f99977533a6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scenes/MirrorAdditiveScenesSubScene.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta new file mode 100644 index 0000000..cb97b32 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9c36b0deb5d9b245b7c97e3d6eeed29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs new file mode 100644 index 0000000..8f2c835 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs @@ -0,0 +1,58 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.AdditiveScenes +{ + [AddComponentMenu("")] + public class AdditiveNetworkManager : NetworkManager + { + [Tooltip("Trigger Zone Prefab")] + public GameObject Zone; + + [Scene] + [Tooltip("Add all sub-scenes to this list")] + public string[] subScenes; + + public override void OnStartServer() + { + base.OnStartServer(); + + // load all subscenes on the server only + StartCoroutine(LoadSubScenes()); + + // Instantiate Zone Handler on server only + Instantiate(Zone); + } + + public override void OnStopServer() + { + StartCoroutine(UnloadScenes()); + } + + public override void OnStopClient() + { + if (mode == NetworkManagerMode.Offline) + StartCoroutine(UnloadScenes()); + } + + IEnumerator LoadSubScenes() + { + Debug.Log("Loading Scenes"); + + foreach (string sceneName in subScenes) + yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); + } + + IEnumerator UnloadScenes() + { + Debug.Log("Unloading Subscenes"); + + foreach (string sceneName in subScenes) + if (SceneManager.GetSceneByName(sceneName).IsValid() || SceneManager.GetSceneByPath(sceneName).IsValid()) + yield return SceneManager.UnloadSceneAsync(sceneName); + + yield return Resources.UnloadUnusedAssets(); + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta new file mode 100644 index 0000000..164d5d7 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 34d1daf9e7dbcb64aa647cb332054ea6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scripts/AdditiveNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs new file mode 100644 index 0000000..ab96c2b --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace Mirror.Examples.AdditiveScenes +{ + // This script demonstrates the NetworkAnimator and how to leverage + // the built-in observers system to track players. + // Note that all ProximityCheckers should be restricted to the Player layer. + public class ShootingTankBehaviour : NetworkBehaviour + { + [SyncVar] + public Quaternion rotation; + + NetworkAnimator networkAnimator; + + [ServerCallback] + void Start() + { + networkAnimator = GetComponent(); + } + + [Range(0, 1)] + public float turnSpeed = 0.1f; + + void Update() + { + if (isServer && netIdentity.observers.Count > 0) + ShootNearestPlayer(); + + if (isClient) + transform.rotation = Quaternion.Slerp(transform.rotation, rotation, turnSpeed); + } + + [Server] + void ShootNearestPlayer() + { + GameObject target = null; + float distance = 100f; + + foreach (NetworkConnectionToClient networkConnection in netIdentity.observers.Values) + { + GameObject tempTarget = networkConnection.identity.gameObject; + float tempDistance = Vector3.Distance(tempTarget.transform.position, transform.position); + + if (target == null || distance > tempDistance) + { + target = tempTarget; + distance = tempDistance; + } + } + + if (target != null) + { + transform.LookAt(new Vector3(target.transform.position.x, 0, target.transform.position.z)); + rotation = transform.rotation; + //networkAnimator.SetTrigger("Shoot"); + } + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta new file mode 100644 index 0000000..e5acc78 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7a25c54cd35eb284eb6b8ed19cf60443 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scripts/ShootingTankBehaviour.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs new file mode 100644 index 0000000..040eaa9 --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs @@ -0,0 +1,42 @@ +using UnityEngine; + +namespace Mirror.Examples.AdditiveScenes +{ + // AdditiveNetworkManager, in OnStartServer, instantiates the prefab only on the server. + // It never exists for clients (other than host client if there is one). + // The prefab has a Sphere Collider with isTrigger = true. + // These OnTrigger events only run on the server and will only send a message to the + // client that entered the Zone to load the subscene assigned to the subscene property. + public class ZoneHandler : MonoBehaviour + { + [Scene] + [Tooltip("Assign the sub-scene to load for this zone")] + public string subScene; + + [ServerCallback] + void OnTriggerEnter(Collider other) + { + // ignore collisions with non-Player objects + if (!other.CompareTag("Player")) return; + + if (other.TryGetComponent(out NetworkIdentity networkIdentity)) + { + SceneMessage message = new SceneMessage { sceneName = subScene, sceneOperation = SceneOperation.LoadAdditive }; + networkIdentity.connectionToClient.Send(message); + } + } + + [ServerCallback] + void OnTriggerExit(Collider other) + { + // ignore collisions with non-Player objects + if (!other.CompareTag("Player")) return; + + if (other.TryGetComponent(out NetworkIdentity networkIdentity)) + { + SceneMessage message = new SceneMessage { sceneName = subScene, sceneOperation = SceneOperation.UnloadAdditive }; + networkIdentity.connectionToClient.Send(message); + } + } + } +} diff --git a/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta new file mode 100644 index 0000000..40d80ec --- /dev/null +++ b/Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 884ed76587eb5854abe6b428b791fdcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AdditiveScenes/Scripts/ZoneHandler.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController.meta b/Assets/Mirror/Examples/AutoLANClientController.meta new file mode 100644 index 0000000..862b090 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0cd55c50fd6654c34a539738afbe0b20 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity b/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity new file mode 100644 index 0000000..fd7f1b5 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity @@ -0,0 +1,3214 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &4023457 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4023458} + - component: {fileID: 4023460} + - component: {fileID: 4023459} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4023458 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4023457} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 757796229} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &4023459 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4023457} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &4023460 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4023457} + m_CullTransparentMesh: 1 +--- !u!1 &30387431 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 30387432} + m_Layer: 5 + m_Name: Manual HUD + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &30387432 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 30387431} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207918714164269} + - {fileID: 1612207917309712325} + - {fileID: 1612207917763321030} + - {fileID: 1612207918780745075} + - {fileID: 757796229} + m_Father: {fileID: 1612207917153820995} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &148002021 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 148002024} + - component: {fileID: 148002023} + - component: {fileID: 148002022} + m_Layer: 0 + m_Name: NetworkSceneScript + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &148002022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 148002021} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a92a11730bf0a4971a014a104eaa9a11, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + clientButton: {fileID: 2048274025} + textResult: {fileID: 2001694449} + panelClient: {fileID: 1793439801} + panelServer: {fileID: 1600308284} +--- !u!114 &148002023 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 148002021} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 2788738206 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!4 &148002024 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 148002021} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &409701480 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 409701481} + - component: {fileID: 409701483} + - component: {fileID: 409701482} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &409701481 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409701480} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1595707137} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &409701482 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409701480} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Client Screen +--- !u!222 &409701483 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 409701480} + m_CullTransparentMesh: 1 +--- !u!1 &552727438 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 552727439} + - component: {fileID: 552727441} + - component: {fileID: 552727440} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &552727439 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552727438} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1681728309} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &552727440 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552727438} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Server Screen +--- !u!222 &552727441 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552727438} + m_CullTransparentMesh: 1 +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &757796228 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 757796229} + - component: {fileID: 757796232} + - component: {fileID: 757796231} + - component: {fileID: 757796230} + m_Layer: 5 + m_Name: InputField (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &757796229 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 757796228} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1341194361} + - {fileID: 4023458} + m_Father: {fileID: 30387432} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 190, y: -251.9971} + m_SizeDelta: {x: 320, y: 80} + m_Pivot: {x: 0, y: 1} +--- !u!114 &757796230 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 757796228} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 757796231} + m_TextComponent: {fileID: 4023459} + m_Placeholder: {fileID: 1341194362} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &757796231 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 757796228} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &757796232 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 757796228} + m_CullTransparentMesh: 1 +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1199576086 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1199576087} + - component: {fileID: 1199576089} + - component: {fileID: 1199576088} + m_Layer: 5 + m_Name: Text Controls + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1199576087 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199576086} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207917153820995} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 19, y: 10} + m_SizeDelta: {x: 620.8444, y: 355.0096} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1199576088 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199576086} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Auto Start button checks for local broadcasting servers, if non found, + one is created. + + Once connected, server and client each have their own UI. + + Clients + can interact and send data to server, as seen via the Button and Text Result.' +--- !u!222 &1199576089 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1199576086} + m_CullTransparentMesh: 1 +--- !u!1 &1341194360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1341194361} + - component: {fileID: 1341194363} + - component: {fileID: 1341194362} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1341194361 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1341194360} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 757796229} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1341194362 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1341194360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Network Address +--- !u!222 &1341194363 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1341194360} + m_CullTransparentMesh: 1 +--- !u!1 &1595707136 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1595707137} + - component: {fileID: 1595707139} + - component: {fileID: 1595707138} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1595707137 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1595707136} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 409701481} + m_Father: {fileID: 1793439802} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -80} + m_SizeDelta: {x: 512, y: 128} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1595707138 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1595707136} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2264151, g: 0.2264151, b: 0.2264151, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1595707139 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1595707136} + m_CullTransparentMesh: 1 +--- !u!1 &1600308284 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1600308285} + m_Layer: 5 + m_Name: Panel Server + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1600308285 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1600308284} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1681728309} + - {fileID: 1627707861} + m_Father: {fileID: 1612207917158590957} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1627707860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1627707861} + - component: {fileID: 1627707863} + - component: {fileID: 1627707862} + m_Layer: 5 + m_Name: Image Result + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1627707861 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1627707860} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2001694448} + m_Father: {fileID: 1600308285} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 380, y: 80} + m_SizeDelta: {x: 230, y: 128} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1627707862 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1627707860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1627707863 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1627707860} + m_CullTransparentMesh: 1 +--- !u!1 &1681728308 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1681728309} + - component: {fileID: 1681728311} + - component: {fileID: 1681728310} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1681728309 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1681728308} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 552727439} + m_Father: {fileID: 1600308285} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 80} + m_SizeDelta: {x: 512, y: 128} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1681728310 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1681728308} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1681728311 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1681728308} + m_CullTransparentMesh: 1 +--- !u!1 &1777369769 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1777369772} + - component: {fileID: 1777369771} + - component: {fileID: 1777369770} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1777369770 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1777369769} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1777369771 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1777369769} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1777369772 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1777369769} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1789070955 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1789070956} + - component: {fileID: 1789070958} + - component: {fileID: 1789070957} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1789070956 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1789070955} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2048274024} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1789070957 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1789070955} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Button +--- !u!222 &1789070958 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1789070955} + m_CullTransparentMesh: 1 +--- !u!1 &1793439801 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1793439802} + m_Layer: 5 + m_Name: Panel Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1793439802 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1793439801} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1595707137} + - {fileID: 2048274024} + m_Father: {fileID: 1612207917158590957} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &2001694447 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2001694448} + - component: {fileID: 2001694450} + - component: {fileID: 2001694449} + m_Layer: 5 + m_Name: Text Result + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2001694448 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001694447} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1627707861} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2001694449 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001694447} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Text Result +--- !u!222 &2001694450 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2001694447} + m_CullTransparentMesh: 1 +--- !u!1 &2048274023 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2048274024} + - component: {fileID: 2048274027} + - component: {fileID: 2048274026} + - component: {fileID: 2048274025} + m_Layer: 5 + m_Name: Button Client + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2048274024 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2048274023} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1789070956} + m_Father: {fileID: 1793439802} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 380, y: -80} + m_SizeDelta: {x: 230, y: 128} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2048274025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2048274023} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2048274026} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2048274026 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2048274023} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2264151, g: 0.2264151, b: 0.2264151, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2048274027 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2048274023} + m_CullTransparentMesh: 1 +--- !u!222 &1612207917049425144 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917049425151} + m_CullTransparentMesh: 1 +--- !u!114 &1612207917049425145 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917049425151} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Auto LAN connector + + Client controlling server Example' +--- !u!224 &1612207917049425150 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917049425151} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207917153820995} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -20} + m_SizeDelta: {x: 800, y: 120} + m_Pivot: {x: 0.5, y: 1} +--- !u!1 &1612207917049425151 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917049425150} + - component: {fileID: 1612207917049425144} + - component: {fileID: 1612207917049425145} + m_Layer: 5 + m_Name: TextWelcome + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1612207917060113808 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917060113809} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207917837318050} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -90, y: 0} + m_SizeDelta: {x: 300, y: 80} + m_Pivot: {x: 1, y: 1} +--- !u!1 &1612207917060113809 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917060113808} + - component: {fileID: 1612207917060113810} + - component: {fileID: 1612207917060113811} + m_Layer: 5 + m_Name: Text Info + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &1612207917060113810 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917060113809} + m_CullTransparentMesh: 1 +--- !u!114 &1612207917060113811 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917060113809} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Info Text +--- !u!1 &1612207917153820992 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917153820995} + - component: {fileID: 1612207917153821021} + - component: {fileID: 1612207917153820994} + m_Layer: 5 + m_Name: PanelStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917153820994 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917153820992} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.5019608} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!224 &1612207917153820995 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917153820992} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207917049425150} + - {fileID: 1612207918225852667} + - {fileID: 1199576087} + - {fileID: 30387432} + m_Father: {fileID: 1612207917837318050} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1612207917153821021 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917153820992} + m_CullTransparentMesh: 1 +--- !u!1 &1612207917158590738 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917158590957} + - component: {fileID: 1612207917158590959} + - component: {fileID: 1612207917158590956} + m_Layer: 5 + m_Name: PanelStop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917158590956 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917158590738} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!224 &1612207917158590957 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917158590738} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207919032404513} + - {fileID: 1600308285} + - {fileID: 1793439802} + m_Father: {fileID: 1612207917837318050} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1612207917158590959 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917158590738} + m_CullTransparentMesh: 1 +--- !u!114 &1612207917309712324 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917309712330} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0, g: 0, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 0, b: 0, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1612207917309712327} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1612207917309712325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917309712330} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207917420016394} + m_Father: {fileID: 30387432} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: -161.99707} + m_SizeDelta: {x: 250, y: 80} + m_Pivot: {x: 0, y: 1} +--- !u!222 &1612207917309712326 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917309712330} + m_CullTransparentMesh: 1 +--- !u!114 &1612207917309712327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917309712330} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1612207917309712330 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917309712325} + - component: {fileID: 1612207917309712326} + - component: {fileID: 1612207917309712327} + - component: {fileID: 1612207917309712324} + m_Layer: 5 + m_Name: ButtonHost + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &1612207917420016388 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917420016395} + m_CullTransparentMesh: 1 +--- !u!114 &1612207917420016389 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917420016395} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Host +--- !u!224 &1612207917420016394 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917420016395} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207917309712325} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1612207917420016395 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917420016394} + - component: {fileID: 1612207917420016388} + - component: {fileID: 1612207917420016389} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917595096356 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917595096362} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Client +--- !u!224 &1612207917595096357 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917595096362} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207918780745075} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1612207917595096359 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917595096362} + m_CullTransparentMesh: 1 +--- !u!1 &1612207917595096362 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917595096357} + - component: {fileID: 1612207917595096359} + - component: {fileID: 1612207917595096356} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917763321024 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917763321031} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1612207917763321025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917763321031} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0, g: 0, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 0, b: 0, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1612207917763321024} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!222 &1612207917763321027 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917763321031} + m_CullTransparentMesh: 1 +--- !u!224 &1612207917763321030 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917763321031} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207918518362062} + m_Father: {fileID: 30387432} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 260, y: -161.99707} + m_SizeDelta: {x: 250, y: 80} + m_Pivot: {x: 0, y: 1} +--- !u!1 &1612207917763321031 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917763321030} + - component: {fileID: 1612207917763321027} + - component: {fileID: 1612207917763321024} + - component: {fileID: 1612207917763321025} + m_Layer: 5 + m_Name: ButtonServer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917837318048 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917837318055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &1612207917837318049 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917837318055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!224 &1612207917837318050 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917837318055} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1612207917153820995} + - {fileID: 1612207917158590957} + - {fileID: 1612207917060113808} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &1612207917837318051 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917837318055} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: -1 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!1 &1612207917837318055 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207917837318050} + - component: {fileID: 1612207917837318051} + - component: {fileID: 1612207917837318048} + - component: {fileID: 1612207917837318049} + - component: {fileID: 1612207917837318077} + m_Layer: 5 + m_Name: CanvasHUD + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207917837318077 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207917837318055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dd6ba23d1fd5945b183ed975a24dbb21, type: 3} + m_Name: + m_EditorClassIdentifier: + alwaysAutoStart: 0 + networkDiscovery: {fileID: 6527795130155115508} + runAsPlayerHost: 0 + PanelStart: {fileID: 1612207917153820992} + PanelStop: {fileID: 1612207917158590738} + buttonHost: {fileID: 1612207917309712324} + buttonServer: {fileID: 1612207917763321025} + buttonClient: {fileID: 1612207918780745074} + buttonStop: {fileID: 1612207919032404512} + buttonAuto: {fileID: 1612207918225852666} + infoText: {fileID: 1612207917060113811} + inputFieldAddress: {fileID: 757796230} +--- !u!1 &1612207918188077504 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918188077507} + - component: {fileID: 1612207918188077533} + - component: {fileID: 1612207918188077506} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207918188077506 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918188077504} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X +--- !u!224 &1612207918188077507 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918188077504} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207919032404513} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1612207918188077533 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918188077504} + m_CullTransparentMesh: 1 +--- !u!222 &1612207918225852660 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918225852664} + m_CullTransparentMesh: 1 +--- !u!114 &1612207918225852661 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918225852664} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1612207918225852664 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918225852667} + - component: {fileID: 1612207918225852660} + - component: {fileID: 1612207918225852661} + - component: {fileID: 1612207918225852666} + m_Layer: 5 + m_Name: ButtonAuto + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207918225852666 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918225852664} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0, g: 0, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 0, b: 0, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1612207918225852661} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1612207918225852667 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918225852664} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207918265142761} + m_Father: {fileID: 1612207917153820995} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -169} + m_SizeDelta: {x: 200, y: 100} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1612207918265142760 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918265142766} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Auto Start +--- !u!224 &1612207918265142761 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918265142766} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207918225852667} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1612207918265142763 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918265142766} + m_CullTransparentMesh: 1 +--- !u!1 &1612207918265142766 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918265142761} + - component: {fileID: 1612207918265142763} + - component: {fileID: 1612207918265142760} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &1612207918518362056 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918518362063} + m_CullTransparentMesh: 1 +--- !u!114 &1612207918518362057 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918518362063} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Server +--- !u!224 &1612207918518362062 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918518362063} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1612207917763321030} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1612207918518362063 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918518362062} + - component: {fileID: 1612207918518362056} + - component: {fileID: 1612207918518362057} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207918714164268 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918714164306} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Manual connecting. +--- !u!224 &1612207918714164269 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918714164306} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 30387432} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: -76} + m_SizeDelta: {x: 510, y: 80} + m_Pivot: {x: 0, y: 1} +--- !u!222 &1612207918714164271 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918714164306} + m_CullTransparentMesh: 1 +--- !u!1 &1612207918714164306 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918714164269} + - component: {fileID: 1612207918714164271} + - component: {fileID: 1612207918714164268} + m_Layer: 5 + m_Name: TextManual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!222 &1612207918780745036 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918780745072} + m_CullTransparentMesh: 1 +--- !u!114 &1612207918780745037 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918780745072} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1612207918780745072 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207918780745075} + - component: {fileID: 1612207918780745036} + - component: {fileID: 1612207918780745037} + - component: {fileID: 1612207918780745074} + m_Layer: 5 + m_Name: ButtonClient + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1612207918780745074 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918780745072} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0, g: 0, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 0, b: 0, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1612207918780745037} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1612207918780745075 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207918780745072} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207917595096357} + m_Father: {fileID: 30387432} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: -252.00409} + m_SizeDelta: {x: 180, y: 80} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1612207919032404512 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207919032404518} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0, g: 0, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 0, b: 0, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1612207919032404515} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1612207919032404513 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207919032404518} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1612207918188077507} + m_Father: {fileID: 1612207917158590957} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 1, y: 1} +--- !u!222 &1612207919032404514 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207919032404518} + m_CullTransparentMesh: 1 +--- !u!114 &1612207919032404515 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1612207919032404518} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &1612207919032404518 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1612207919032404513} + - component: {fileID: 1612207919032404514} + - component: {fileID: 1612207919032404515} + - component: {fileID: 1612207919032404512} + m_Layer: 5 + m_Name: ButtonStop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &4058379193819526388 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4058379193819526397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37536f0bfd25347478e4b742ee9144fa, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 4058379193819526394} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 0} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + canvasHUD: {fileID: 0} +--- !u!4 &4058379193819526393 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4058379193819526397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4058379193819526394 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4058379193819526397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 1 +--- !u!1 &4058379193819526397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4058379193819526393} + - component: {fileID: 4058379193819526394} + - component: {fileID: 4058379193819526388} + - component: {fileID: 6527795130155115508} + m_Layer: 0 + m_Name: NetworkDiscovery + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &6527795130155115508 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4058379193819526397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ae7e7ce4a60904a8d927cce7422254c9, type: 3} + m_Name: + m_EditorClassIdentifier: + enableActiveDiscovery: 1 + BroadcastAddress: + serverBroadcastListenPort: 47777 + ActiveDiscoveryInterval: 3 + transport: {fileID: 4058379193819526394} + secretHandshake: -1693891328078065144 + canvasHUD: {fileID: 1612207917837318077} diff --git a/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity.meta b/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity.meta new file mode 100644 index 0000000..aab2fdd --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 8e092fa854dbe4a24b7489ecd5b5b9fe +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/MirrorAutoLANClientController.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Prefabs.meta b/Assets/Mirror/Examples/AutoLANClientController/Prefabs.meta new file mode 100644 index 0000000..643368a --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 95af4e8f5594e4d08b1c7b8e19d9d1a9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab b/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab new file mode 100644 index 0000000..34a3612 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2448974773247019605 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2051395529432152427} + - component: {fileID: 4941989115671398543} + m_Layer: 0 + m_Name: PlayerController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2051395529432152427 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2448974773247019605} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4941989115671398543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2448974773247019605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1453846501 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab.meta b/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab.meta new file mode 100644 index 0000000..74ac945 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2b6efbce53c9140b88da2ec384c5a120 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/Prefabs/PlayerController.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts.meta b/Assets/Mirror/Examples/AutoLANClientController/Scripts.meta new file mode 100644 index 0000000..230f950 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 91173fa2b44114e4e9edee569086a354 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs new file mode 100644 index 0000000..89b7fef --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs @@ -0,0 +1,105 @@ +using System; +using System.Net; +using UnityEngine; +using UnityEngine.Events; +using Mirror.Discovery; + + +//[Serializable] +//public class ServerFoundUnityEvent : UnityEvent { }; +namespace Mirror.Examples.AutoLANClientController +{ + [DisallowMultipleComponent] + [AddComponentMenu("Network/Network Discovery")] + public class AutoLANNetworkDiscovery : NetworkDiscoveryBase + { + #region Server + public CanvasHUD canvasHUD; + + ///

+ /// Process the request from a client + /// + /// + /// Override if you wish to provide more information to the clients + /// such as the name of the host player + /// + /// Request coming from client + /// Address of the client that sent the request + /// The message to be sent back to the client or null + protected override ServerResponse ProcessRequest(ServerRequest request, IPEndPoint endpoint) + { + // In this case we don't do anything with the request + // but other discovery implementations might want to use the data + // in there, This way the client can ask for + // specific game mode or something + + try + { + // this is an example reply message, return your own + // to include whatever is relevant for your game + return new ServerResponse + { + serverId = ServerId, + uri = transport.ServerUri() + }; + } + catch (NotImplementedException) + { + Debug.LogError($"Transport {transport} does not support network discovery"); + throw; + } + } + + #endregion + + #region Client + + /// + /// Create a message that will be broadcasted on the network to discover servers + /// + /// + /// Override if you wish to include additional data in the discovery message + /// such as desired game mode, language, difficulty, etc... + /// An instance of ServerRequest with data to be broadcasted + protected override ServerRequest GetRequest() => new ServerRequest(); + + /// + /// Process the answer from a server + /// + /// + /// A client receives a reply from a server, this method processes the + /// reply and raises an event + /// + /// Response that came from the server + /// Address of the server that replied + protected override void ProcessResponse(ServerResponse response, IPEndPoint endpoint) + { + // we received a message from the remote endpoint + response.EndPoint = endpoint; + + // although we got a supposedly valid url, we may not be able to resolve + // the provided host + // However we know the real ip address of the server because we just + // received a packet from it, so use that as host. + UriBuilder realUri = new UriBuilder(response.uri) + { + Host = response.EndPoint.Address.ToString() + }; + response.uri = realUri.Uri; + + //OnServerFound.Invoke(response); + if (canvasHUD == null) + { +#if UNITY_2022_2_OR_NEWER + canvasHUD = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + canvasHUD = GameObject.FindObjectOfType(); +#endif + } + canvasHUD.OnDiscoveredServer(response); + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs.meta b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs.meta new file mode 100644 index 0000000..0e4d552 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ae7e7ce4a60904a8d927cce7422254c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkDiscovery.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs new file mode 100644 index 0000000..392e282 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs @@ -0,0 +1,336 @@ +using System; +using UnityEngine; +using UnityEngine.SceneManagement; +using Mirror; +using System.Linq; + +/* + Documentation: https://mirror-networking.gitbook.io/docs/components/network-manager + API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkManager.html +*/ +namespace Mirror.Examples.AutoLANClientController +{ + public class AutoLANNetworkManager : NetworkManager + { + // Overrides the base singleton so we don't + // have to cast to this type everywhere. + public static new AutoLANNetworkManager singleton { get; private set; } + + public CanvasHUD canvasHUD; + private NetworkIdentity[] copyOfOwnedObjects; + + /// + /// Runs on both Server and Client + /// Networking is NOT initialized when this fires + /// + public override void Awake() + { + base.Awake(); + singleton = this; + } + + #region Unity Callbacks + + public override void OnValidate() + { + base.OnValidate(); + } + + /// + /// Runs on both Server and Client + /// Networking is NOT initialized when this fires + /// + public override void Start() + { + base.Start(); + if (canvasHUD == null) + { +#if UNITY_2022_2_OR_NEWER + canvasHUD = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + canvasHUD = GameObject.FindObjectOfType(); +#endif + } + } + + /// + /// Runs on both Server and Client + /// + public override void LateUpdate() + { + base.LateUpdate(); + } + + /// + /// Runs on both Server and Client + /// + public override void OnDestroy() + { + base.OnDestroy(); + //UnityEngine.Debug.Log("OnDestroy"); + } + +#endregion + + #region Start & Stop + + /// + /// Set the frame rate for a headless server. + /// Override if you wish to disable the behavior or set your own tick rate. + /// + public override void ConfigureHeadlessFrameRate() + { + base.ConfigureHeadlessFrameRate(); + } + + /// + /// called when quitting the application by closing the window / pressing stop in the editor + /// + public override void OnApplicationQuit() + { + base.OnApplicationQuit(); + //UnityEngine.Debug.Log("OnApplicationQuit"); + } + + #endregion + + #region Scene Management + + /// + /// This causes the server to switch scenes and sets the networkSceneName. + /// Clients that connect to this server will automatically switch to this scene. This is called automatically if onlineScene or offlineScene are set, but it can be called from user code to switch scenes again while the game is in progress. This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready() again to participate in the new scene. + /// + /// + public override void ServerChangeScene(string newSceneName) + { + base.ServerChangeScene(newSceneName); + //UnityEngine.Debug.Log("ServerChangeScene"); + } + + /// + /// Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed + /// This allows server to do work / cleanup / prep before the scene changes. + /// + /// Name of the scene that's about to be loaded + public override void OnServerChangeScene(string newSceneName) + { + //UnityEngine.Debug.Log("OnServerChangeScene"); + } + + /// + /// Called on the server when a scene is completed loaded, when the scene load was initiated by the server with ServerChangeScene(). + /// + /// The name of the new scene. + public override void OnServerSceneChanged(string sceneName) + { + //UnityEngine.Debug.Log("OnServerSceneChanged"); + } + + /// + /// Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed + /// This allows client to do work / cleanup / prep before the scene changes. + /// + /// Name of the scene that's about to be loaded + /// Scene operation that's about to happen + /// true to indicate that scene loading will be handled through overrides + public override void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) + { + //UnityEngine.Debug.Log("OnClientChangeScene"); + } + + /// + /// Called on clients when a scene has completed loaded, when the scene load was initiated by the server. + /// Scene changes can cause player objects to be destroyed. The default implementation of OnClientSceneChanged in the NetworkManager is to add a player object for the connection if no player object exists. + /// + public override void OnClientSceneChanged() + { + base.OnClientSceneChanged(); + // UnityEngine.Debug.Log("OnClientSceneChanged"); + } + + #endregion + + #region Server System Callbacks + + /// + /// Called on the server when a new client connects. + /// Unity calls this on the Server when a Client connects to the Server. Use an override to tell the NetworkManager what to do when a client connects to the server. + /// + /// Connection from client. + public override void OnServerConnect(NetworkConnectionToClient conn) + { + //UnityEngine.Debug.Log("OnServerConnect"); + canvasHUD.SetupInfoText("A client connected."); + } + + /// + /// Called on the server when a client is ready. + /// The default implementation of this function calls NetworkServer.SetClientReady() to continue the network setup process. + /// + /// Connection from client. + public override void OnServerReady(NetworkConnectionToClient conn) + { + base.OnServerReady(conn); + //UnityEngine.Debug.Log("OnServerReady"); + } + + /// + /// Called on the server when a client adds a new player with ClientScene.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnectionToClient conn) + { + base.OnServerAddPlayer(conn); + //UnityEngine.Debug.Log("OnServerAddPlayer"); + } + + /// + /// Called on the server when a client disconnects. + /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. + /// + /// Connection from client. + public override void OnServerDisconnect(NetworkConnectionToClient conn) + { + // this code is to reset any objects belonging to disconnected clients + // make a copy because the original collection will change in the loop + copyOfOwnedObjects = conn.owned.ToArray(); + // Loop the copy, skipping the player object. + // RemoveClientAuthority on everything else + foreach (NetworkIdentity identity in copyOfOwnedObjects) + { + if (identity != conn.identity) + identity.RemoveClientAuthority(); + } + + base.OnServerDisconnect(conn); + //UnityEngine.Debug.Log("OnServerDisconnect"); + canvasHUD.SetupInfoText("A client disconnected."); + } + + /// + /// Called on server when transport raises an error. + /// NetworkConnection may be null. + /// + /// Connection of the client...may be null + /// TransportError enum + /// String message of the error. + public override void OnServerError(NetworkConnectionToClient conn, TransportError transportError, string message) + { + UnityEngine.Debug.Log("OnServerError"); + canvasHUD.SetupInfoText("OnServerError: " + message); + } + + #endregion + + #region Client System Callbacks + + /// + /// Called on the client when connected to a server. + /// The default implementation of this function sets the client as ready and adds a player. Override the function to dictate what happens when the client connects. + /// + public override void OnClientConnect() + { + base.OnClientConnect(); + //UnityEngine.Debug.Log("OnClientConnect"); + canvasHUD.SetupInfoText("Connected to server."); + } + + /// + /// Called on clients when disconnected from a server. + /// This is called on the client when it disconnects from the server. Override this function to decide what happens when the client disconnects. + /// + public override void OnClientDisconnect() + { + //UnityEngine.Debug.Log("OnClientDisconnect"); + canvasHUD.SetupInfoText("Disconnected from server."); + } + + /// + /// Called on clients when a servers tells the client it is no longer ready. + /// This is commonly used when switching scenes. + /// + public override void OnClientNotReady() + { + //UnityEngine.Debug.Log("OnClientNotReady"); + } + + /// + /// Called on client when transport raises an error. + /// + /// TransportError enum. + /// String message of the error. + public override void OnClientError(TransportError transportError, string message) + { + UnityEngine.Debug.Log("OnClientError"); + canvasHUD.SetupInfoText("OnClientError: " + message); + } + + #endregion + + #region Start & Stop Callbacks + + // Since there are multiple versions of StartServer, StartClient and StartHost, to reliably customize + // their functionality, users would need override all the versions. Instead these callbacks are invoked + // from all versions, so users only need to implement this one case. + + /// + /// This is invoked when a host is started. + /// StartHost has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartHost() + { + //UnityEngine.Debug.Log("OnStartHost"); + canvasHUD.SetupInfoText("Started Hosting."); + } + + /// + /// This is invoked when a server is started - including when a host is started. + /// StartServer has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartServer() + { + //UnityEngine.Debug.Log("OnStartServer"); + canvasHUD.SetupInfoText("Started server."); + } + + /// + /// This is invoked when the client is started. + /// + public override void OnStartClient() + { + //UnityEngine.Debug.Log("OnStartClient"); + canvasHUD.SetupInfoText("Client started."); + } + + /// + /// This is called when a host is stopped. + /// + public override void OnStopHost() + { + //UnityEngine.Debug.Log("OnStopHost"); + canvasHUD.SetupInfoText("Hosting stopped."); + } + + /// + /// This is called when a server is stopped - including when a host is stopped. + /// + public override void OnStopServer() + { + //UnityEngine.Debug.Log("OnStopServer"); + canvasHUD.SetupInfoText("Server stopped."); + } + + /// + /// This is called when a client is stopped. + /// + public override void OnStopClient() + { + //UnityEngine.Debug.Log("OnStopClient"); + canvasHUD.SetupInfoText("Client stopped."); + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs.meta b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs.meta new file mode 100644 index 0000000..af5efec --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 37536f0bfd25347478e4b742ee9144fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/Scripts/AutoLANNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs b/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs new file mode 100644 index 0000000..0cfc69b --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs @@ -0,0 +1,204 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Mirror; +using UnityEngine.UI; +using Mirror.Discovery; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.AutoLANClientController +{ + public class CanvasHUD : MonoBehaviour + { + // this will check for games to join, if non, start host. + public bool alwaysAutoStart = false; + public AutoLANNetworkDiscovery networkDiscovery; + readonly Dictionary discoveredServers = new Dictionary(); + public bool runAsPlayerHost = false; + + // UI + public GameObject PanelStart, PanelStop; + public Button buttonHost, buttonServer, buttonClient, buttonStop, buttonAuto; + public Text infoText; + // legacy inputfield interaction does not auto bring up a keyboard on headset builds, use tmp. + public InputField inputFieldAddress; + + private void Start() + { + //Make sure to attach these Buttons in the Inspector + buttonHost.onClick.AddListener(ButtonHost); + buttonServer.onClick.AddListener(ButtonServer); + buttonClient.onClick.AddListener(ButtonClient); + buttonStop.onClick.AddListener(ButtonStop); + buttonAuto.onClick.AddListener(ButtonAuto); + + //Update the canvas text if you have manually changed network managers address from the game object before starting the game scene + inputFieldAddress.text = NetworkManager.singleton.networkAddress; + + //Adds a listener to the input field and invokes a method when the value changes. + inputFieldAddress.onValueChanged.AddListener(delegate { OnValueChangedAddress(); }); + + if (networkDiscovery == null) + { +#if UNITY_2022_2_OR_NEWER + networkDiscovery = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + networkDiscovery = GameObject.FindObjectOfType(); +#endif + } + + // skips waiting for users to press ui button + if (alwaysAutoStart) + { + StartCoroutine(Waiter()); + } + } + + public IEnumerator Waiter() + { + infoText.text = "Discovering servers.."; + discoveredServers.Clear(); + networkDiscovery.StartDiscovery(); + // we have set this as 3.1 seconds, default discovery scan is 3 seconds, allows some time if host and client are started at same time + yield return new WaitForSeconds(3.1f); + if (discoveredServers == null || discoveredServers.Count <= 0) + { + if (runAsPlayerHost == true) + { + infoText.text = "No Servers found, starting as Host."; + } + else + { + infoText.text = "No Servers found, starting as Server."; + } + yield return new WaitForSeconds(1.0f); + discoveredServers.Clear(); + // NetworkManager.singleton.onlineScene = SceneManager.GetActiveScene().name; + if (runAsPlayerHost == true) + { + NetworkManager.singleton.StartHost(); + } + else + { + NetworkManager.singleton.StartServer(); + } + networkDiscovery.AdvertiseServer(); + } + } + + void Connect(ServerResponse info) + { + infoText.text = "Connecting to: " + info.serverId; + networkDiscovery.StopDiscovery(); + NetworkManager.singleton.StartClient(info.uri); + } + + public void OnDiscoveredServer(ServerResponse info) + { + discoveredServers[info.serverId] = info; + Connect(info); + } + + public void ButtonHost() + { + SetupInfoText("Starting as host"); + discoveredServers.Clear(); + //NetworkManager.singleton.onlineScene = SceneManager.GetActiveScene().name; + NetworkManager.singleton.StartHost(); + networkDiscovery.AdvertiseServer(); + + } + + public void ButtonServer() + { + SetupInfoText("Starting as server."); + discoveredServers.Clear(); + // NetworkManager.singleton.onlineScene = SceneManager.GetActiveScene().name; + NetworkManager.singleton.StartServer(); + networkDiscovery.AdvertiseServer(); + + } + + public void ButtonClient() + { + SetupInfoText("Starting as client."); + discoveredServers.Clear(); + networkDiscovery.StartDiscovery(); + } + + public void ButtonStop() + { + SetupInfoText("Stopping."); + // stop host if host mode + if (NetworkServer.active && NetworkClient.isConnected) + { + NetworkManager.singleton.StopHost(); + } + // stop client if client-only + else if (NetworkClient.isConnected) + { + NetworkManager.singleton.StopClient(); + } + // stop server if server-only + else if (NetworkServer.active) + { + NetworkManager.singleton.StopServer(); + } + networkDiscovery.StopDiscovery(); + // we need to call setup canvas a second time in this function for it to update the abovee changes + SetupCanvas(); + } + + public void ButtonAuto() + { + SetupInfoText("Auto Starting."); + StartCoroutine(Waiter()); + } + + // manually call canvas changes for performance, can lazily be done via Update() + public void SetupCanvas() + { + // Here we will dump majority of the canvas UI + + if (NetworkManager.singleton == null) + { + SetupInfoText("NetworkManager null"); + return; + } + + // check network status, and show required UI + if (!NetworkClient.isConnected && !NetworkServer.active) + { + if (NetworkClient.active) + { + PanelStart.SetActive(false); + PanelStop.SetActive(true); + } + else + { + PanelStart.SetActive(true); + PanelStop.SetActive(false); + } + } + else + { + PanelStart.SetActive(false); + PanelStop.SetActive(true); + } + } + + // useful status info to display on screen + public void SetupInfoText(string _info) + { + infoText.text = _info; + SetupCanvas(); + } + + // Invoked when the value of the text field changes. + public void OnValueChangedAddress() + { + NetworkManager.singleton.networkAddress = inputFieldAddress.text; + } + } +} diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs.meta b/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs.meta new file mode 100644 index 0000000..c15965a --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: dd6ba23d1fd5945b183ed975a24dbb21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/Scripts/CanvasHUD.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs b/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs new file mode 100644 index 0000000..a1366d4 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Mirror; +using UnityEngine.UI; + +namespace Mirror.Examples.AutoLANClientController +{ + public class NetworkSceneScript : NetworkBehaviour + { + + public Button clientButton; + public Text textResult; + public GameObject panelClient, panelServer; + + void Start() + { + clientButton.onClick.AddListener(ClientButton); + + panelServer.SetActive(false); + panelClient.SetActive(false); + + if (isServer) + { + panelServer.SetActive(true); + + } + if (isClient) + { + panelClient.SetActive(true); + } + } + + void ClientButton() + { + if (isClient) + { + CmdSendText("Text: " + Random.Range(0, 999)); + } + } + + [Command(requiresAuthority = false)] + public void CmdSendText(string _value) + { + textResult.text = _value; + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs.meta b/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs.meta new file mode 100644 index 0000000..959f651 --- /dev/null +++ b/Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a92a11730bf0a4971a014a104eaa9a11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/AutoLANClientController/Scripts/NetworkSceneScript.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic.meta b/Assets/Mirror/Examples/Basic.meta new file mode 100644 index 0000000..653ea78 --- /dev/null +++ b/Assets/Mirror/Examples/Basic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ea49fcefbc864e19a94091a170fc06c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Basic/Prefabs.meta b/Assets/Mirror/Examples/Basic/Prefabs.meta new file mode 100644 index 0000000..234c22a --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f821a97809492a479cac0843442e245 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab new file mode 100644 index 0000000..4315c0e --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab @@ -0,0 +1,73 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &897184729387425976 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 897184729387425978} + - component: {fileID: 897184729387425977} + - component: {fileID: 8550999602067651493} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &897184729387425978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &897184729387425977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 137866334 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &8550999602067651493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 897184729387425976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a472ac3ae1701d149861871cf416a46d, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + playerUIPrefab: {fileID: 5152941909035078397, guid: 22f1fa3a0aff72b46a371f667bb4fb30, + type: 3} + playerNumber: 0 + playerColor: + serializedVersion: 2 + rgba: 4294967295 + playerData: 0 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..1906ca7 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: dc2c4328591bef748abb8df795c17202 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Prefabs/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab new file mode 100644 index 0000000..2dda39c --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab @@ -0,0 +1,250 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &507587715476979468 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7941985369064644521} + - component: {fileID: 263176703837159862} + - component: {fileID: 862087973501639025} + m_Layer: 5 + m_Name: PlayerDataText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7941985369064644521 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5939842025755258307} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 60, y: -45} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &263176703837159862 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_CullTransparentMesh: 0 +--- !u!114 &862087973501639025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 507587715476979468} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 22 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: 'Data: 000' +--- !u!1 &5152941909035078397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5939842025755258307} + - component: {fileID: 6858069060858394075} + - component: {fileID: 1130938342127810670} + - component: {fileID: 1800193220786703771} + m_Layer: 5 + m_Name: PlayerUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5939842025755258307 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 290719538378481902} + - {fileID: 7941985369064644521} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 120, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6858069060858394075 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_CullTransparentMesh: 0 +--- !u!114 &1130938342127810670 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1800193220786703771 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5152941909035078397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 64acca8c87e5ceb44bcbd56ef21e2950, type: 3} + m_Name: + m_EditorClassIdentifier: + image: {fileID: 1130938342127810670} + playerNameText: {fileID: 2551726036882886172} + playerDataText: {fileID: 862087973501639025} +--- !u!1 &5516013313779480533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 290719538378481902} + - component: {fileID: 1473077327790139714} + - component: {fileID: 2551726036882886172} + m_Layer: 5 + m_Name: PlayerNameText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &290719538378481902 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5939842025755258307} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 60, y: -15} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1473077327790139714 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_CullTransparentMesh: 0 +--- !u!114 &2551726036882886172 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5516013313779480533} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 22 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: Player 00 diff --git a/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta new file mode 100644 index 0000000..f1546a3 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 22f1fa3a0aff72b46a371f667bb4fb30 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Prefabs/PlayerUI.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/README.md b/Assets/Mirror/Examples/Basic/README.md new file mode 100644 index 0000000..5b39b3a --- /dev/null +++ b/Assets/Mirror/Examples/Basic/README.md @@ -0,0 +1,16 @@ +# Basic Example + +This is a bare bones example of a running game with Network Manager and UI prefab players: + +1. Remove all scenes from Build Settings, then add the Example scene alone. + +2. Open the Example scene and build the project. + +3. In the editor, click Play, and Server + Client or Server Only...it will be listening on port 7777. + - If you clicked Host (Server + Client), the host player will appear as Player 00. + +4. Run one or more instances (up to 16 total players) of the built application. + +5. Click Client on each instance. + +6. Now you will see all players in the editor and the clients, all with data being updated and synchronized. diff --git a/Assets/Mirror/Examples/Basic/README.md.meta b/Assets/Mirror/Examples/Basic/README.md.meta new file mode 100644 index 0000000..cd0f4de --- /dev/null +++ b/Assets/Mirror/Examples/Basic/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 67177defd4d334a549e535f10506cc66 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/README.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Scenes.meta b/Assets/Mirror/Examples/Basic/Scenes.meta new file mode 100644 index 0000000..0c751c6 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16f46473489d3364badc2f37c4db8634 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity b/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity new file mode 100644 index 0000000..ddd8069 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity @@ -0,0 +1,746 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &249891953 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 249891957} + - component: {fileID: 249891954} + - component: {fileID: 249891956} + - component: {fileID: 249891955} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &249891954 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &249891955 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &249891956 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 20460c43f0320ed4baf8c1dcf953eafa, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 249891955} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 897184729387425976, guid: dc2c4328591bef748abb8df795c17202, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 +--- !u!4 &249891957 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 249891953} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -10, y: 4, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &288173824 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 288173827} + - component: {fileID: 288173826} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &288173826 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 288173824} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &288173827 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 288173824} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &379082678 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 379082679} + - component: {fileID: 379082681} + - component: {fileID: 379082682} + - component: {fileID: 379082680} + - component: {fileID: 379082683} + m_Layer: 5 + m_Name: PlayersPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &379082679 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 864730913} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 2.5} + m_SizeDelta: {x: -10, y: -15} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &379082680 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 5 + m_Top: 5 + m_Bottom: 5 + m_ChildAlignment: 0 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 120, y: 65} + m_Spacing: {x: 20, y: 20} + m_Constraint: 0 + m_ConstraintCount: 2 +--- !u!222 &379082681 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_CullTransparentMesh: 0 +--- !u!114 &379082682 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.039215688} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &379082683 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 379082678} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &533055200 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 533055204} + - component: {fileID: 533055203} + - component: {fileID: 533055202} + - component: {fileID: 533055201} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &533055201 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 266fac335be17a243af86e88de84766d, type: 3} + m_Name: + m_EditorClassIdentifier: + mainPanel: {fileID: 1712119861} + playersPanel: {fileID: 379082679} +--- !u!114 &533055202 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &533055203 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &533055204 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 533055200} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1712119861} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &864730912 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 864730913} + - component: {fileID: 864730916} + - component: {fileID: 864730914} + m_Layer: 5 + m_Name: BorderPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &864730913 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 379082679} + m_Father: {fileID: 1712119861} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -55} + m_SizeDelta: {x: -40, y: -150} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &864730914 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 0 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &864730916 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864730912} + m_CullTransparentMesh: 0 +--- !u!1 &1356257340 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1356257343} + - component: {fileID: 1356257342} + - component: {fileID: 1356257341} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1356257341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1356257342 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1356257343 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1356257340} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1712119860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1712119861} + - component: {fileID: 1712119863} + - component: {fileID: 1712119862} + m_Layer: 5 + m_Name: MainPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1712119861 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 864730913} + m_Father: {fileID: 533055204} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1712119862 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1712119863 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1712119860} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity.meta b/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity.meta new file mode 100644 index 0000000..32503db --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b30904751905d3f4dacde62ac85ec7c2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Scenes/MirrorBasic.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Scripts.meta b/Assets/Mirror/Examples/Basic/Scripts.meta new file mode 100644 index 0000000..5cc0800 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c5291659f25af9409bbc25a2d37d628 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs new file mode 100644 index 0000000..508c15f --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace Mirror.Examples.Basic +{ + [AddComponentMenu("")] + public class BasicNetManager : NetworkManager + { + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnectionToClient conn) + { + base.OnServerAddPlayer(conn); + Player.ResetPlayerNumbers(); + } + + /// + /// Called on the server when a client disconnects. + /// This is called on the Server when a Client disconnects from the Server. Use an override to decide what should happen when a disconnection is detected. + /// + /// Connection from client. + public override void OnServerDisconnect(NetworkConnectionToClient conn) + { + base.OnServerDisconnect(conn); + Player.ResetPlayerNumbers(); + } + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta new file mode 100644 index 0000000..04e1975 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 20460c43f0320ed4baf8c1dcf953eafa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Scripts/BasicNetManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs new file mode 100644 index 0000000..7e7adb9 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +namespace Mirror.Examples.Basic +{ + public class CanvasUI : MonoBehaviour + { + [Tooltip("Assign Main Panel so it can be turned on from Player:OnStartClient")] + public RectTransform mainPanel; + + [Tooltip("Assign Players Panel for instantiating PlayerUI as child")] + public RectTransform playersPanel; + + // static instance that can be referenced from static methods below. + static CanvasUI instance; + + void Awake() + { + instance = this; + } + + public static void SetActive(bool active) + { + instance.mainPanel.gameObject.SetActive(active); + } + + public static RectTransform GetPlayersPanel() => instance.playersPanel; + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta new file mode 100644 index 0000000..7e6d86c --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 266fac335be17a243af86e88de84766d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Scripts/CanvasUI.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Scripts/Player.cs b/Assets/Mirror/Examples/Basic/Scripts/Player.cs new file mode 100644 index 0000000..c095be4 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/Player.cs @@ -0,0 +1,181 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Examples.Basic +{ + [AddComponentMenu("")] + public class Player : NetworkBehaviour + { + // Events that the PlayerUI will subscribe to + public event System.Action OnPlayerNumberChanged; + public event System.Action OnPlayerColorChanged; + public event System.Action OnPlayerDataChanged; + + // Players List to manage playerNumber + static readonly List playersList = new List(); + + [Header("Player UI")] + public GameObject playerUIPrefab; + + GameObject playerUIObject; + PlayerUI playerUI = null; + + #region SyncVars + + [Header("SyncVars")] + + /// + /// This is appended to the player name text, e.g. "Player 01" + /// + [SyncVar(hook = nameof(PlayerNumberChanged))] + public byte playerNumber = 0; + + /// + /// Random color for the playerData text, assigned in OnStartServer + /// + [SyncVar(hook = nameof(PlayerColorChanged))] + public Color32 playerColor = Color.white; + + /// + /// This is updated by UpdateData which is called from OnStartServer via InvokeRepeating + /// + [SyncVar(hook = nameof(PlayerDataChanged))] + public ushort playerData = 0; + + // This is called by the hook of playerNumber SyncVar above + void PlayerNumberChanged(byte _, byte newPlayerNumber) + { + OnPlayerNumberChanged?.Invoke(newPlayerNumber); + } + + // This is called by the hook of playerColor SyncVar above + void PlayerColorChanged(Color32 _, Color32 newPlayerColor) + { + OnPlayerColorChanged?.Invoke(newPlayerColor); + } + + // This is called by the hook of playerData SyncVar above + void PlayerDataChanged(ushort _, ushort newPlayerData) + { + OnPlayerDataChanged?.Invoke(newPlayerData); + } + + #endregion + + #region Server + + /// + /// This is invoked for NetworkBehaviour objects when they become active on the server. + /// This could be triggered by NetworkServer.Listen() for objects in the scene, or by NetworkServer.Spawn() for objects that are dynamically created. + /// This will be called for objects on a "host" as well as for object on a dedicated server. + /// + public override void OnStartServer() + { + base.OnStartServer(); + + // Add this to the static Players List + playersList.Add(this); + + // set the Player Color SyncVar + playerColor = Random.ColorHSV(0f, 1f, 0.9f, 0.9f, 1f, 1f); + + // set the initial player data + playerData = (ushort)Random.Range(100, 1000); + + // Start generating updates + InvokeRepeating(nameof(UpdateData), 1, 1); + } + + // This is called from BasicNetManager OnServerAddPlayer and OnServerDisconnect + // Player numbers are reset whenever a player joins / leaves + [ServerCallback] + internal static void ResetPlayerNumbers() + { + byte playerNumber = 0; + foreach (Player player in playersList) + player.playerNumber = playerNumber++; + } + + // This only runs on the server, called from OnStartServer via InvokeRepeating + [ServerCallback] + void UpdateData() + { + playerData = (ushort)Random.Range(100, 1000); + } + + /// + /// Invoked on the server when the object is unspawned + /// Useful for saving object data in persistent storage + /// + public override void OnStopServer() + { + CancelInvoke(); + playersList.Remove(this); + } + + #endregion + + #region Client + + /// + /// Called on every NetworkBehaviour when it is activated on a client. + /// Objects on the host have this function called, as there is a local client on the host. The values of SyncVars on object are guaranteed to be initialized correctly with the latest state from the server when this function is called on the client. + /// + public override void OnStartClient() + { + // Instantiate the player UI as child of the Players Panel + playerUIObject = Instantiate(playerUIPrefab, CanvasUI.GetPlayersPanel()); + playerUI = playerUIObject.GetComponent(); + + // wire up all events to handlers in PlayerUI + OnPlayerNumberChanged = playerUI.OnPlayerNumberChanged; + OnPlayerColorChanged = playerUI.OnPlayerColorChanged; + OnPlayerDataChanged = playerUI.OnPlayerDataChanged; + + // Invoke all event handlers with the initial data from spawn payload + OnPlayerNumberChanged.Invoke(playerNumber); + OnPlayerColorChanged.Invoke(playerColor); + OnPlayerDataChanged.Invoke(playerData); + } + + /// + /// Called when the local player object has been set up. + /// This happens after OnStartClient(), as it is triggered by an ownership message from the server. This is an appropriate place to activate components or functionality that should only be active for the local player, such as cameras and input. + /// + public override void OnStartLocalPlayer() + { + // Set isLocalPlayer for this Player in UI for background shading + playerUI.SetLocalPlayer(); + + // Activate the main panel + CanvasUI.SetActive(true); + } + + /// + /// Called when the local player object is being stopped. + /// This happens before OnStopClient(), as it may be triggered by an ownership message from the server, or because the player object is being destroyed. This is an appropriate place to deactivate components or functionality that should only be active for the local player, such as cameras and input. + /// + public override void OnStopLocalPlayer() + { + // Disable the main panel for local player + CanvasUI.SetActive(false); + } + + /// + /// This is invoked on clients when the server has caused this object to be destroyed. + /// This can be used as a hook to invoke effects or do client specific cleanup. + /// + public override void OnStopClient() + { + // disconnect event handlers + OnPlayerNumberChanged = null; + OnPlayerColorChanged = null; + OnPlayerDataChanged = null; + + // Remove this player's UI object + Destroy(playerUIObject); + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta new file mode 100644 index 0000000..60e80d4 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/Player.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: a472ac3ae1701d149861871cf416a46d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Scripts/Player.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs new file mode 100644 index 0000000..e3fe6c9 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs @@ -0,0 +1,41 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.Basic +{ + public class PlayerUI : MonoBehaviour + { + [Header("Player Components")] + public Image image; + + [Header("Child Text Objects")] + public Text playerNameText; + public Text playerDataText; + + // Sets a highlight color for the local player + public void SetLocalPlayer() + { + // add a visual background for the local player in the UI + image.color = new Color(1f, 1f, 1f, 0.1f); + } + + // This value can change as clients leave and join + public void OnPlayerNumberChanged(byte newPlayerNumber) + { + playerNameText.text = string.Format("Player {0:00}", newPlayerNumber); + } + + // Random color set by Player::OnStartServer + public void OnPlayerColorChanged(Color32 newPlayerColor) + { + playerNameText.color = newPlayerColor; + } + + // This updates from Player::UpdateData via InvokeRepeating on server + public void OnPlayerDataChanged(ushort newPlayerData) + { + // Show the data in the UI + playerDataText.text = string.Format("Data: {0:000}", newPlayerData); + } + } +} diff --git a/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta new file mode 100644 index 0000000..b045950 --- /dev/null +++ b/Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 64acca8c87e5ceb44bcbd56ef21e2950 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Basic/Scripts/PlayerUI.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark.meta b/Assets/Mirror/Examples/Benchmark.meta new file mode 100644 index 0000000..73801df --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a0b6db5b77ec4177a6e47b68ea7d064 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Benchmark/Materials.meta b/Assets/Mirror/Examples/Benchmark/Materials.meta new file mode 100644 index 0000000..12a3156 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba4e4f7749e6b437aac187bd7625cf28 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat new file mode 100644 index 0000000..5c24968 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta new file mode 100644 index 0000000..ef50299 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/Red.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 451c5da2c5056496297cffba02216286 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Materials/Red.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Materials/White.mat b/Assets/Mirror/Examples/Benchmark/Materials/White.mat new file mode 100644 index 0000000..aaf3087 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/White.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta b/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta new file mode 100644 index 0000000..1fab0d1 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Materials/White.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: ff8f106e5c9e34da28ad9cee6edb2255 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Materials/White.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs.meta b/Assets/Mirror/Examples/Benchmark/Prefabs.meta new file mode 100644 index 0000000..2cdde64 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29276b4f741904266bb3eb6331bee4ab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab new file mode 100644 index 0000000..5af7fc2 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab @@ -0,0 +1,152 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 8309506939003697769} + m_Layer: 0 + m_Name: Monster + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 451c5da2c5056496297cffba02216286, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2156230198 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2697352357490696306} + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 0 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 1 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &8309506939003697769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9cddc2e496c474e538a494465be0192a, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + speed: 1 + movementProbability: 0.1 + movementDistance: 20 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta new file mode 100644 index 0000000..586f895 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 30b8f251d03d84284b70601e691d474f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Prefabs/Monster.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab new file mode 100644 index 0000000..2e69a8f --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab @@ -0,0 +1,150 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 644305951047116972} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8f106e5c9e34da28ad9cee6edb2255, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 91522075 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2697352357490696306} + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 0 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 1 + showOverlay: 1 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &644305951047116972 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c482338c8cc6d4a3cba81934c0151972, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + speed: 20 diff --git a/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..3bcd912 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e1299008405d14b17b1ca459a6cd44a2 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Prefabs/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Scenes.meta b/Assets/Mirror/Examples/Benchmark/Scenes.meta new file mode 100644 index 0000000..f73c636 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1507ce547cd6a42ddb4ba60c3552dc48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity b/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity new file mode 100644 index 0000000..22e7db6 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity @@ -0,0 +1,538 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 80 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 96 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.39215687, g: 0.58431375, b: 0.92941177, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 35 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956} + m_LocalPosition: {x: 0, y: 50, z: -80} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + - component: {fileID: 1282001523} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f0f6e2c4566084948a433ee5285d3fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 449802645721213856, guid: e1299008405d14b17b1ca459a6cd44a2, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 449802645721213856, guid: 30b8f251d03d84284b70601e691d474f, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 1 + spawnPrefab: {fileID: 449802645721213856, guid: 30b8f251d03d84284b70601e691d474f, + type: 3} + spawnAmount: 1000 + interleave: 1 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 39adc6e09d5544ed955a50ce8600355a, type: 3} + m_Name: + m_EditorClassIdentifier: + visRange: 30 + rebuildInterval: 1 + checkMethod: 0 + showSlider: 1 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d7da4e566d24ea7b0e12178d934b648, type: 3} + m_Name: + m_EditorClassIdentifier: + clientIntervalReceivedPackets: 0 + clientIntervalReceivedBytes: 0 + clientIntervalSentPackets: 0 + clientIntervalSentBytes: 0 + clientReceivedPacketsPerSecond: 0 + clientReceivedBytesPerSecond: 0 + clientSentPacketsPerSecond: 0 + clientSentBytesPerSecond: 0 + serverIntervalReceivedPackets: 0 + serverIntervalReceivedBytes: 0 + serverIntervalSentPackets: 0 + serverIntervalSentBytes: 0 + serverReceivedPacketsPerSecond: 0 + serverReceivedBytesPerSecond: 0 + serverSentPacketsPerSecond: 0 + serverSentBytesPerSecond: 0 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity.meta b/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity.meta new file mode 100644 index 0000000..15ffdb2 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 3b956c7d68b6144dd8e6c36636e25b52 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Scenes/MirrorBenchmark.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Scripts.meta b/Assets/Mirror/Examples/Benchmark/Scripts.meta new file mode 100644 index 0000000..7247026 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56ec73164c7f24072b822ed0d1e4d03e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs new file mode 100644 index 0000000..786369f --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs @@ -0,0 +1,52 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + [AddComponentMenu("")] + public class BenchmarkNetworkManager : NetworkManager + { + [Header("Spawns")] + public GameObject spawnPrefab; + public int spawnAmount = 5000; + public float interleave = 1; + + void SpawnAll() + { + // calculate sqrt so we can spawn N * N = Amount + float sqrt = Mathf.Sqrt(spawnAmount); + + // calculate spawn xz start positions + // based on spawnAmount * distance + float offset = -sqrt / 2 * interleave; + + // spawn exactly the amount, not one more. + int spawned = 0; + for (int spawnX = 0; spawnX < sqrt; ++spawnX) + { + for (int spawnZ = 0; spawnZ < sqrt; ++spawnZ) + { + // spawn exactly the amount, not any more + // (our sqrt method isn't 100% precise) + if (spawned < spawnAmount) + { + // instantiate & position + GameObject go = Instantiate(spawnPrefab); + float x = offset + spawnX * interleave; + float z = offset + spawnZ * interleave; + go.transform.position = new Vector3(x, 0, z); + + // spawn + NetworkServer.Spawn(go); + ++spawned; + } + } + } + } + + public override void OnStartServer() + { + base.OnStartServer(); + SpawnAll(); + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta new file mode 100644 index 0000000..55f8109 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f0f6e2c4566084948a433ee5285d3fb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Scripts/BenchmarkNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs new file mode 100644 index 0000000..f5fcc29 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs @@ -0,0 +1,57 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + public class MonsterMovement : NetworkBehaviour + { + public float speed = 1; + + // movement probability: + // 0.5 is too high, monsters are moving almost all the time. + // only-sync-on-change shows no difference with 0.5 at all. + // in other words: broken change detection would be too easy to miss! + [Header("Note: use 0.1 to test change detection, 0.5 is too high!")] + public float movementProbability = 0.1f; + public float movementDistance = 20; + + bool moving; + Vector3 start; + Vector3 destination; + + public override void OnStartServer() + { + start = transform.position; + } + + [ServerCallback] + void Update() + { + if (moving) + { + if (Vector3.Distance(transform.position, destination) <= 0.01f) + { + transform.position = destination; + moving = false; + } + else + { + transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime); + } + } + else + { + float r = Random.value; + if (r < movementProbability * Time.deltaTime) + { + Vector2 circlePos = Random.insideUnitCircle; + Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); + + // set destination on random pos in a circle around start. + // (don't want to wander off) + destination = start + dir * movementDistance; + moving = true; + } + } + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta new file mode 100644 index 0000000..a22ba28 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9cddc2e496c474e538a494465be0192a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Scripts/MonsterMovement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs new file mode 100644 index 0000000..c400113 --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace Mirror.Examples.Benchmark +{ + public class PlayerMovement : NetworkBehaviour + { + public float speed = 5; + + // naming for easier debugging + public override void OnStartClient() + { + name = $"Player[{netId}|{(isLocalPlayer ? "local" : "remote")}]"; + } + + public override void OnStartServer() + { + name = $"Player[{netId}|server]"; + } + + void Update() + { + if (!isLocalPlayer) return; + + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + Vector3 dir = new Vector3(h, 0, v); + transform.position += dir.normalized * (Time.deltaTime * speed); + } + } +} diff --git a/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta new file mode 100644 index 0000000..506d54a --- /dev/null +++ b/Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c482338c8cc6d4a3cba81934c0151972 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Benchmark/Scripts/PlayerMovement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle.meta b/Assets/Mirror/Examples/BenchmarkIdle.meta new file mode 100644 index 0000000..dba267d --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8cdce54a5125843aeb2a7ca5db3e4dd4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs b/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs new file mode 100644 index 0000000..536a8fd --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs @@ -0,0 +1,98 @@ +using UnityEngine; + +namespace Mirror.Examples.BenchmarkIdle +{ + [AddComponentMenu("")] + public class BenchmarkIdleNetworkManager : NetworkManager + { + [Header("Spawns")] + public int spawnAmount = 10_000; + public float interleave = 1; + public GameObject spawnPrefab; + + // player spawn positions should be spread across the world. + // not all at one place. + // but _some_ at the same place. + // => deterministic random is ideal + [Range(0, 1)] public float spawnPositionRatio = 0.01f; + + System.Random random = new System.Random(42); + + void SpawnAll() + { + // clear previous player spawn positions in case we start twice + foreach (Transform position in startPositions) + Destroy(position.gameObject); + + startPositions.Clear(); + + // calculate sqrt so we can spawn N * N = Amount + float sqrt = Mathf.Sqrt(spawnAmount); + + // calculate spawn xz start positions + // based on spawnAmount * distance + float offset = -sqrt / 2 * interleave; + + // spawn exactly the amount, not one more. + int spawned = 0; + for (int spawnX = 0; spawnX < sqrt; ++spawnX) + { + for (int spawnZ = 0; spawnZ < sqrt; ++spawnZ) + { + // spawn exactly the amount, not any more + // (our sqrt method isn't 100% precise) + if (spawned < spawnAmount) + { + // spawn & position + GameObject go = Instantiate(spawnPrefab); + float x = offset + spawnX * interleave; + float z = offset + spawnZ * interleave; + Vector3 position = new Vector3(x, 0, z); + go.transform.position = position; + + // spawn + NetworkServer.Spawn(go); + ++spawned; + + // add random spawn position for players. + // don't have them all in the same place. + if (random.NextDouble() <= spawnPositionRatio) + { + GameObject spawnGO = new GameObject("Spawn"); + spawnGO.transform.position = position; + spawnGO.AddComponent(); + } + } + } + } + } + + // overwrite random spawn position selection: + // - needs to be deterministic so every CCU test results in the same + // - needs to be random so not only are the spawn positions spread out + // randomly, we also have a random amount of players per spawn position + public override Transform GetStartPosition() + { + // first remove any dead transforms + startPositions.RemoveAll(t => t == null); + + if (startPositions.Count == 0) + return null; + + // pick a random one + int index = random.Next(0, startPositions.Count); // DETERMINISTIC + return startPositions[index]; + } + + public override void OnStartServer() + { + base.OnStartServer(); + SpawnAll(); + + // disable rendering on server to reduce noise in profiling. + // keep enabled in host mode though. + if (mode == NetworkManagerMode.ServerOnly) + Camera.main.enabled = false; + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs.meta b/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs.meta new file mode 100644 index 0000000..cdfb420 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6f7f7192969f04e1eb1d3b30cb378a20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/BenchmarkIdleNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity b/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity new file mode 100644 index 0000000..fc1558b --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity @@ -0,0 +1,519 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 35 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956} + m_LocalPosition: {x: 0, y: 100, z: -150} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 1 +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001523} + - component: {fileID: 1282001524} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6f7f7192969f04e1eb1d3b30cb378a20, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001524} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 449802645721213856, guid: c07d22724e9914db19b931058fd2111e, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 449802645721213856, guid: 0ea79775d59804682a8cdd46b3811344, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + spawnAmount: 10000 + interleave: 2 + spawnPrefab: {fileID: 449802645721213856, guid: 0ea79775d59804682a8cdd46b3811344, + type: 3} + spawnPositionRatio: 0.01 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d7da4e566d24ea7b0e12178d934b648, type: 3} + m_Name: + m_EditorClassIdentifier: + clientIntervalReceivedPackets: 0 + clientIntervalReceivedBytes: 0 + clientIntervalSentPackets: 0 + clientIntervalSentBytes: 0 + clientReceivedPacketsPerSecond: 0 + clientReceivedBytesPerSecond: 0 + clientSentPacketsPerSecond: 0 + clientSentBytesPerSecond: 0 + serverIntervalReceivedPackets: 0 + serverIntervalReceivedBytes: 0 + serverIntervalSentPackets: 0 + serverIntervalSentBytes: 0 + serverReceivedPacketsPerSecond: 0 + serverReceivedBytesPerSecond: 0 + serverSentPacketsPerSecond: 0 + serverSentBytesPerSecond: 0 +--- !u!114 &1282001524 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7424c1070fad4ba2a7a96b02fbeb4bb, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + NoDelay: 1 + SendTimeout: 5000 + ReceiveTimeout: 30000 + serverMaxMessageSize: 16384 + serverMaxReceivesPerTick: 10000 + serverSendQueueLimitPerConnection: 10000 + serverReceiveQueueLimitPerConnection: 10000 + clientMaxMessageSize: 16384 + clientMaxReceivesPerTick: 1000 + clientSendQueueLimit: 10000 + clientReceiveQueueLimit: 10000 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity.meta b/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity.meta new file mode 100644 index 0000000..084b2cc --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 23a7fdebddb0e4caabec9f7777f799f0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/MirrorBenchmarkIdle.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs b/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs new file mode 100644 index 0000000..7c9bd8d --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs @@ -0,0 +1,39 @@ +// idle object that rarely gets dirty +using UnityEngine; + +namespace Mirror.Examples.BenchmarkIdle +{ + public class Npc : NetworkBehaviour + { + // component to assign in inspector + public Renderer rend; + + // the value to set dirty + [SyncVar] ulong value; + + [Tooltip("Probability that this object just sleeps the whole time without ever getting dirty. (Npcs, Item drops, etc.)")] + [Range(0, 1)] public float sleepingProbability = 0.80f; // 80% of the objects are sleeping + bool sleeping; + + [Header("Colors")] + public Color activeColor = Color.white; + public Color sleepingColor = Color.red; + + public override void OnStartServer() + { + sleeping = Random.value < sleepingProbability; + + // color coding + // can't do this in update, it's too expensive + rend.material.color = sleeping ? sleepingColor : activeColor; + } + + [ServerCallback] + void Update() + { + // set dirty if not sleeping. + // only counts as dirty every 'syncInterval'. + if (!sleeping) ++value; + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs.meta b/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs.meta new file mode 100644 index 0000000..ca25ac1 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 112eda4d75f3840238a75926c4d465bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Npc.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat b/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat new file mode 100644 index 0000000..6e2a110 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Npc + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat.meta b/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat.meta new file mode 100644 index 0000000..7964695 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 3ec830ed62de74cfe8c71892397c32ee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Npc.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab b/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab new file mode 100644 index 0000000..bd9ccc1 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab @@ -0,0 +1,119 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: -3181616459286004871} + m_Layer: 0 + m_Name: Npc + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 451c5da2c5056496297cffba02216286, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 104829785 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-3181616459286004871 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 112eda4d75f3840238a75926c4d465bf, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + rend: {fileID: 6692327599609520039} + sleepingProbability: 0.8 + activeColor: {r: 1, g: 1, b: 1, a: 1} + sleepingColor: {r: 1, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab.meta b/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab.meta new file mode 100644 index 0000000..8e23375 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0ea79775d59804682a8cdd46b3811344 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Npc.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.cs b/Assets/Mirror/Examples/BenchmarkIdle/Player.cs new file mode 100644 index 0000000..83261e3 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.cs @@ -0,0 +1,87 @@ +using UnityEngine; + +namespace Mirror.Examples.BenchmarkIdle +{ + public class Player : NetworkBehaviour + { + // automated movement. + // player may switch to manual movement any time + [Header("Automated Movement")] + public bool autoMove = true; + public float autoSpeed = 2; + public float movementProbability = 0.5f; + public float movementDistance = 20; + bool moving; + Vector3 start; + Vector3 destination; + + [Header("Manual Movement")] + public float manualSpeed = 10; + + // cache .transform for benchmark demo. + // Component.get_transform shows in profiler otherwise. + Transform tf; + + public override void OnStartLocalPlayer() + { + tf = transform; + start = tf.position; + } + + void AutoMove() + { + if (moving) + { + if (Vector3.Distance(tf.position, destination) <= 0.01f) + { + moving = false; + } + else + { + tf.position = Vector3.MoveTowards(tf.position, destination, autoSpeed * Time.deltaTime); + } + } + else + { + float r = Random.value; + if (r < movementProbability * Time.deltaTime) + { + // calculate a random position in a circle + float circleX = Mathf.Cos(Random.value * Mathf.PI); + float circleZ = Mathf.Sin(Random.value * Mathf.PI); + Vector2 circlePos = new Vector2(circleX, circleZ); + Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); + + // set destination on random pos in a circle around start. + // (don't want to wander off) + destination = start + dir * movementDistance; + moving = true; + } + } + } + + void ManualMove() + { + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + Vector3 direction = new Vector3(h, 0, v); + transform.position += direction.normalized * (Time.deltaTime * manualSpeed); + } + + static bool Interrupted() => + Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0; + + void Update() + { + if (!isLocalPlayer) return; + + // player may interrupt auto movement to switch to manual + if (Interrupted()) autoMove = false; + + // move + if (autoMove) AutoMove(); + else ManualMove(); + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.cs.meta b/Assets/Mirror/Examples/BenchmarkIdle/Player.cs.meta new file mode 100644 index 0000000..12e59cb --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c4bfbc9d9d08147c3966a2661650986a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Player.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.mat b/Assets/Mirror/Examples/BenchmarkIdle/Player.mat new file mode 100644 index 0000000..aa2c056 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.mat.meta b/Assets/Mirror/Examples/BenchmarkIdle/Player.mat.meta new file mode 100644 index 0000000..f5942ee --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: d420d3b9c6ea54d8392b48f1cfa2e91c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Player.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab b/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab new file mode 100644 index 0000000..8341c82 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab @@ -0,0 +1,154 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 8691745481282286165} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8f106e5c9e34da28ad9cee6edb2255, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3219404471 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2697352357490696306} + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 0 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &8691745481282286165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c4bfbc9d9d08147c3966a2661650986a, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + autoMove: 1 + autoSpeed: 2 + movementProbability: 0.5 + movementDistance: 20 + manualSpeed: 10 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab.meta b/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab.meta new file mode 100644 index 0000000..a148978 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c07d22724e9914db19b931058fd2111e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt b/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt new file mode 100644 index 0000000..673d30e --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt @@ -0,0 +1,9 @@ +This is used for CCU tests. +White = players, Red = monsters. + +In NetworkManager: +- set the server's IP/Port +- enable 'auto start headless server', build server binary. +- enable 'auto connect headless client', build client binary. + +Launch 1 server with N clients. \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt.meta b/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt.meta new file mode 100644 index 0000000..343d5c9 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f470f284e61694f03b862ce57768786d +timeCreated: 1678260514 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt b/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt new file mode 100644 index 0000000..a7031fb --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt @@ -0,0 +1,4 @@ +Benchmark with majority idle objects to test dirtyObjects technique. + +This is generating large traffic. +The test requires Telepathy in order to not disconnect the client. \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt.meta b/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt.meta new file mode 100644 index 0000000..0eb416c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c00df365757142c3b4b835df96eba59b +timeCreated: 1690899527 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkIdle/_Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction.meta b/Assets/Mirror/Examples/BenchmarkPrediction.meta new file mode 100644 index 0000000..99e6512 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e90270b475f740d69548d4ed4ef5f7a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat b/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat new file mode 100644 index 0000000..7506ca9 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: BallMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 1 + - _Metallic: 1 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat.meta b/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat.meta new file mode 100644 index 0000000..10f1f86 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 09fe33013804145e8a4ba1d18f834dcf +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/BallMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity b/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity new file mode 100644 index 0000000..e1af26e --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity @@ -0,0 +1,1002 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &3512376 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3512380} + - component: {fileID: 3512379} + - component: {fileID: 3512378} + - component: {fileID: 3512377} + m_Layer: 0 + m_Name: SideWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &3512377 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3512376} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &3512378 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3512376} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &3512379 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3512376} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &3512380 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3512376} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -5, y: 2.5, z: 0} + m_LocalScale: {x: 10, y: 5, z: 0.1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!1 &11554784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 11554788} + - component: {fileID: 11554787} + - component: {fileID: 11554786} + - component: {fileID: 11554785} + m_Layer: 0 + m_Name: SideWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &11554785 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 11554784} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &11554786 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 11554784} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &11554787 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 11554784} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &11554788 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 11554784} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 5, y: 2.5, z: 0} + m_LocalScale: {x: 10, y: 5, z: 0.1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!1 &191084098 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 191084102} + - component: {fileID: 191084101} + - component: {fileID: 191084100} + - component: {fileID: 191084099} + m_Layer: 0 + m_Name: TopWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &191084099 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191084098} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &191084100 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191084098} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &191084101 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191084098} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &191084102 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 191084098} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 5, z: 0} + m_LocalScale: {x: 10, y: 0.1, z: 10} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &333653952 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 333653956} + - component: {fileID: 333653955} + - component: {fileID: 333653954} + - component: {fileID: 333653953} + m_Layer: 0 + m_Name: SideWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &333653953 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 333653952} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &333653954 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 333653952} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &333653955 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 333653952} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &333653956 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 333653952} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 2.5, z: -5} + m_LocalScale: {x: 10, y: 5, z: 0.1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &703590129 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 703590131} + - component: {fileID: 703590130} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &703590130 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 703590129} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &703590131 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 703590129} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1192486254 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1192486258} + - component: {fileID: 1192486257} + - component: {fileID: 1192486256} + - component: {fileID: 1192486255} + m_Layer: 0 + m_Name: SideWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &1192486255 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192486254} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1192486256 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192486254} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1192486257 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192486254} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1192486258 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192486254} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 2.5, z: 5} + m_LocalScale: {x: 10, y: 5, z: 0.1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1343329356 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1343329360} + - component: {fileID: 1343329359} + - component: {fileID: 1343329358} + - component: {fileID: 1343329357} + m_Layer: 0 + m_Name: BottomWall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 2147483647 + m_IsActive: 1 +--- !u!65 &1343329357 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1343329356} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1343329358 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1343329356} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5afe569b0e1434398b94cf6c73e90c89, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1343329359 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1343329356} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1343329360 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1343329356} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 10, y: 0.1, z: 10} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1432777610 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1432777613} + - component: {fileID: 1432777612} + - component: {fileID: 1432777611} + - component: {fileID: 1432777614} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1432777611 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432777610} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1432777612 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432777610} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f96c236d30fd94a75a172a7642242637, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1432777611} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 6080703956733773953, guid: feea51e51b4564f06a38482bbebac8fa, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: + - {fileID: 5646305152014201295, guid: 881505c283e224c4fbe4e03127f08b4a, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + spawnAmount: 1000 + spawnPrefab: {fileID: 5646305152014201295, guid: 881505c283e224c4fbe4e03127f08b4a, + type: 3} + spawnArea: + m_Center: {x: 0, y: 2.5, z: 0} + m_Extent: {x: 5, y: 2.5, z: 5} +--- !u!4 &1432777613 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432777610} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1432777614 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432777610} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!1 &2101508988 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2101508991} + - component: {fileID: 2101508990} + - component: {fileID: 2101508989} + - component: {fileID: 2101508992} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &2101508989 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2101508988} + m_Enabled: 1 +--- !u!20 &2101508990 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2101508988} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &2101508991 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2101508988} + m_LocalRotation: {x: -0.016399357, y: 0.9638876, z: -0.06110458, w: -0.25868532} + m_LocalPosition: {x: 7.708386, y: 3.4294498, z: 13.220224} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2101508992 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2101508988} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity.meta b/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity.meta new file mode 100644 index 0000000..497b309 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 26e96d86a94c2451d85dcabf4aff3551 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/MirrorPredictionBenchmark.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs b/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs new file mode 100644 index 0000000..e969ee6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs @@ -0,0 +1,50 @@ +using UnityEngine; + +namespace Mirror.Examples.PredictionBenchmark +{ + [AddComponentMenu("")] + public class NetworkManagerPredictionBenchmark : NetworkManager + { + [Header("Spawns")] + public int spawnAmount = 1000; + public GameObject spawnPrefab; + public Bounds spawnArea = new Bounds(new Vector3(0, 2.5f, 0), new Vector3(10f, 5f, 10f)); + + public override void Awake() + { + base.Awake(); + + // ensure vsync is disabled for the benchmark, otherwise results are capped + QualitySettings.vSyncCount = 0; + } + + void SpawnAll() + { + // spawn randomly inside the cage + for (int i = 0; i < spawnAmount; ++i) + { + // choose a random point within the cage + float x = Random.Range(spawnArea.min.x, spawnArea.max.x); + float y = Random.Range(spawnArea.min.y, spawnArea.max.y); + float z = Random.Range(spawnArea.min.z, spawnArea.max.z); + Vector3 position = new Vector3(x, y, z); + + // spawn & position + GameObject go = Instantiate(spawnPrefab); + go.transform.position = position; + NetworkServer.Spawn(go); + } + } + + public override void OnStartServer() + { + base.OnStartServer(); + SpawnAll(); + + // disable rendering on server to reduce noise in profiling. + // keep enabled in host mode though. + if (mode == NetworkManagerMode.ServerOnly) + Camera.main.enabled = false; + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs.meta b/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs.meta new file mode 100644 index 0000000..8de66ad --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f96c236d30fd94a75a172a7642242637 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/NetworkManagerPredictionBenchmark.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab b/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab new file mode 100644 index 0000000..d787f4c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6080703956733773953 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5774152995658786670} + - component: {fileID: 4958697633604052194} + m_Layer: 0 + m_Name: PlayerSpectator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5774152995658786670 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6080703956733773953} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4958697633604052194 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6080703956733773953} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2913940975 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab.meta b/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab.meta new file mode 100644 index 0000000..dec2245 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: feea51e51b4564f06a38482bbebac8fa +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/PlayerSpectator.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab b/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab new file mode 100644 index 0000000..cc8c75a --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab @@ -0,0 +1,186 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5646305152014201295 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5646305152014201299} + - component: {fileID: 5646305152014201298} + - component: {fileID: 5646305152014201297} + - component: {fileID: 5646305152014201296} + - component: {fileID: 1898357413811911178} + - component: {fileID: 7187875016326091757} + - component: {fileID: 1900383403885999746} + - component: {fileID: 813163234907249251} + m_Layer: 0 + m_Name: PredictedBall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5646305152014201299 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 2.5, z: 0} + m_LocalScale: {x: 0.35, y: 0.35, z: 0.35} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5646305152014201298 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &5646305152014201297 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 09fe33013804145e8a4ba1d18f834dcf, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!135 &5646305152014201296 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1898357413811911178 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 0 + m_CollisionDetection: 1 +--- !u!114 &7187875016326091757 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3958841676 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &1900383403885999746 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d38927cdc6024b9682b5fe9778b9ef99, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + predictedRigidbody: {fileID: 0} + mode: 1 + motionSmoothingVelocityThreshold: 0.1 + motionSmoothingAngularVelocityThreshold: 0.1 + motionSmoothingTimeTolerance: 0.5 + stateHistoryLimit: 32 + recordInterval: 0.05 + onlyRecordChanges: 1 + compareLastFirst: 1 + positionCorrectionThreshold: 0.1 + rotationCorrectionThreshold: 5 + oneFrameAhead: 1 + snapThreshold: 2 + showGhost: 0 + ghostVelocityThreshold: 0.1 + localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320, type: 2} + remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776, type: 2} + checkGhostsEveryNthFrame: 4 + positionInterpolationSpeed: 15 + rotationInterpolationSpeed: 10 + teleportDistanceMultiplier: 10 + reduceSendsWhileIdle: 1 +--- !u!114 &813163234907249251 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5646305152014201295} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 87a6103a0a29544ba9f303c8a3b7407c, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + force: 10 + interval: 3 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab.meta b/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab.meta new file mode 100644 index 0000000..318ec42 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 881505c283e224c4fbe4e03127f08b4a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/PredictedBall.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs b/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs new file mode 100644 index 0000000..5a0cbe7 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs @@ -0,0 +1,52 @@ +using UnityEngine; + +namespace Mirror.Examples.PredictionBenchmark +{ + public class RandomForce : NetworkBehaviour + { + public float force = 10; + public float interval = 3; + PredictedRigidbody prediction; + Rigidbody rb => prediction.predictedRigidbody; + + void Awake() + { + prediction = GetComponent(); + } + + // every(!) connected client adds force to all objects(!) + // the more clients, the more crazier it gets. + // this is intentional for benchmarks. + public override void OnStartClient() + { + // start at a random time, but repeat at a fixed time + float randomStart = Random.Range(0, interval); + InvokeRepeating(nameof(ApplyForce), randomStart, interval); + } + + + [ClientCallback] + void ApplyForce() + { + // calculate force in random direction but always upwards + Vector2 direction2D = Random.insideUnitCircle; + Vector3 direction3D = new Vector3(direction2D.x, 1.0f, direction2D.y); + Vector3 impulse = direction3D * force; + + // grab the current Rigidbody from PredictedRigidbody. + // sometimes this is on a ghost object, so always grab it live: + + + // predicted locally and sync to server for others to see. + // PredictedRigidbody will take care of corrections automatically. + rb.AddForce(impulse, ForceMode.Impulse); + CmdApplyForce(impulse); + } + + [Command(requiresAuthority = false)] // everyone can call this + void CmdApplyForce(Vector3 impulse) + { + rb.AddForce(impulse, ForceMode.Impulse); + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs.meta b/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs.meta new file mode 100644 index 0000000..8237439 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 87a6103a0a29544ba9f303c8a3b7407c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/RandomForce.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md b/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md new file mode 100644 index 0000000..f927773 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md @@ -0,0 +1,24 @@ +Mirror's PredictedRigidbody is optimized for low end devices / VR. +While not interacting with the object, there's zero overhead! +While interacting, overhead comes from sync & corrections. + +This benchmark has predicted objects which are constantly synced & corrected. +=> This is not a real world scenario, it's worst case that we can use for profiling! +=> As a Mirror user you don't need to worry about this demo. + +# Benchmark Setup +- Unity 2021.3 LTS +- IL2CPP Builds +- M1 Macbook Pro +- vsync disabled in NetworkManagerPredictionBenchmark.cs + +# Benchmark Results History for 1000 objects without ghosts: +Not Predicted: 1000 FPS Client, 2500 FPS Server +Predicted: + 2024-03-13: 500 FPS Client, 1700 FPS Server + 2024-03-13: 580 FPS Client, 1700 FPS Server // micro optimizations + 2024-03-14: 590 FPS Client, 1700 FPS Server // UpdateGhosting() every 4th frame + 2024-03-14: 615 FPS Client, 1700 FPS Server // predictedRigidbodyTransform.GetPositionAndRotation() + 2024-03-15: 625 FPS Client, 1700 FPS Server // Vector3.MoveTowardsCustom() + 2024-03-18: 628 FPS Client, 1700 FPS Server // removed O(N) insertion from CorrectHistory() + 2024-03-28: 800 FPS Client, 1700 FPS Server // FAST mode prediction diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md.meta b/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md.meta new file mode 100644 index 0000000..e2fd860 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/Readme.md.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ef1cc472cf2141baa667b35be391340a +timeCreated: 1710305999 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/Readme.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat b/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat new file mode 100644 index 0000000..39c0212 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WallMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 0} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat.meta b/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat.meta new file mode 100644 index 0000000..cea0636 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5afe569b0e1434398b94cf6c73e90c89 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkPrediction/WallMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak.meta new file mode 100644 index 0000000..7064854 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d21d00f41432a4816ac9c0b70d8be22d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset b/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset new file mode 100644 index 0000000..b8e45cb --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b345aa8c625f48c42b128a3818160fa1, type: 3} + m_Name: BehaviourConfig + m_EditorClassIdentifier: + _moveBehaviour: + SinYMove: + _minSpeed: 0.5 + _maxSpeed: 1 + _minAmplitude: 0.5 + _maxAmplitude: 1 + _positionMaxRandom: 100 + SinAllAxisMove: + _minSpeed: 0.5 + _maxSpeed: 1 + _amplitude: 50 + WanderMove: + _circleRadius: 35 + _turnChance: 0.05 + _maxRadius: 2000 + _mass: 15 + _maxSpeed: 3 + _maxForce: 15 + _maxSpawnPositionRadius: 100 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset.meta new file mode 100644 index 0000000..a63ea97 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 7d859fe3222918f4e9b2fe25afa82ced +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/BehaviourConfig.asset + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies.meta new file mode 100644 index 0000000..bae9b5e --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 913218514ba0544029c119cb49d8a73c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer.meta new file mode 100644 index 0000000..c153d2e --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6212bba711d2346469b9b11112c59a43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md new file mode 100644 index 0000000..5763977 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 StinkySteak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md.meta new file mode 100644 index 0000000..0adf360 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b0c6073310113462d96a86bea89ec4ea +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/LICENSE.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md new file mode 100644 index 0000000..d293297 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md @@ -0,0 +1,63 @@ +# Simulation Timer +An Lightweight Efficient Timer for Unity. Inspired by Photon Fusion TickTimer +## Usage/Examples + +#### Simulation Timer + +![](https://github.com/StinkySteak/com.stinkysteak.simulationtimer/blob/main/Gif/DefaultTimer.gif) + +```csharp +private SimulationTimer _disableTimer; + +private void Start() +{ + _disableTimer = SimulationTimer.CreateFromSeconds(_delay); +} + +private void Update() +{ + if(_disableTimer.IsExpired()) + { + _gameObject.SetActive(false); + _disableTimer = SimulationTimer.None; + } +} +``` + +#### Pauseable Simulation Timer + +![](https://github.com/StinkySteak/com.stinkysteak.simulationtimer/blob/main/Gif/PauseableTimer.gif) + +```csharp +private PauseableSimulationTimer _timer; + +public PauseableSimulationTimer Timer => _timer; + +private void Start() +{ + _timer = PauseableSimulationTimer.CreateFromSeconds(_delay); +} + +public void TogglePause() +{ + if(!_timer.IsPaused) + { + _timer.Pause(); + return; + } + + _timer.Resume(); +} + +private void Update() +{ + if(_timer.IsExpired()) + { + _gameObject.SetActive(false); + _timer = PauseableSimulationTimer.None; + } +} +``` +## Class Reference +`SimulationTimer`: Default Timer +`PauseableTimer`: Pauseable Timer diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md.meta new file mode 100644 index 0000000..3cb15ef --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ee0478529536d0c4982dac64c0021021 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/README.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime.meta new file mode 100644 index 0000000..cd87a4b --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97dc55e998bbf3443b386473b013a62c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs new file mode 100644 index 0000000..f211c6c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs @@ -0,0 +1,63 @@ +using UnityEngine; + +namespace StinkySteak.SimulationTimer +{ + public struct PauseableSimulationTimer + { + public static PauseableSimulationTimer None => default; + + private float _targetTime; + private bool _isPaused; + + private float _pauseAtTime; + + public float TargetTime => GetTargetTime(); + public bool IsPaused => _isPaused; + + private float GetTargetTime() + { + if (!_isPaused) + { + return _targetTime; + } + + return _targetTime + Time.time - _pauseAtTime; + } + + public static PauseableSimulationTimer CreateFromSeconds(float duration) + { + return new PauseableSimulationTimer() + { + _targetTime = duration + Time.time + }; + } + + public void Pause() + { + if (_isPaused) return; + + _isPaused = true; + _pauseAtTime = Time.time; + } + + public void Resume() + { + if (!_isPaused) return; + + _targetTime = GetTargetTime(); + _isPaused = false; + _pauseAtTime = 0; + } + + public bool IsRunning => _targetTime > 0; + + public bool IsExpired() + => Time.time >= TargetTime && IsRunning; + + public bool IsExpiredOrNotRunning() + => Time.time >= TargetTime; + + public float RemainingSeconds + => Mathf.Max(TargetTime - Time.time, 0); + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs.meta new file mode 100644 index 0000000..5929060 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b1ad3772cd6fb4848a960ac3a397aaa0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/PauseableSimulationTimer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs new file mode 100644 index 0000000..bda4ee1 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace StinkySteak.SimulationTimer +{ + public struct SimulationTimer + { + public static SimulationTimer None => default; + + private float _targetTime; + + public float TargetTime => _targetTime; + + public static SimulationTimer CreateFromSeconds(float duration) + { + return new SimulationTimer() + { + _targetTime = duration + Time.time + }; + } + + public bool IsRunning => _targetTime > 0; + + public bool IsExpired() + => Time.time >= _targetTime && IsRunning; + + public bool IsExpiredOrNotRunning() + => Time.time >= _targetTime; + + public float RemainingSeconds + => Mathf.Max(_targetTime - Time.time, 0); + } +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs.meta new file mode 100644 index 0000000..57c090f --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c3dc5b6ba56d2c94b8078dc70de8d5c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/Runtime/SimulationTimer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json new file mode 100644 index 0000000..055326a --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json @@ -0,0 +1,15 @@ +{ + "name": "com.stinkysteak.simulationtimer", + "version": "0.1.0", + "displayName": "Simulation Timer", + "description": "Efficient and Scalable Frame Timer", + "unity": "2021.3", + "documentationUrl": "https://github.com/StinkySteak/com.stinkysteak.simulationtimer", + "changelogUrl": "https://github.com/StinkySteak/com.stinkysteak.simulationtimer/blob/main/CHANGELOG.md", + "licensesUrl": "https://github.com/StinkySteak/com.stinkysteak.simulationtimer/blob/main/LICENSE.md", + "author": { + "name": "Stinkysteak", + "email": "stinkysteak@steaksoft.com", + "url": "https://steaksoft.net" + } + } \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json.meta new file mode 100644 index 0000000..b30f888 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: eb3de65e983cc7f4caaed498f0a300ff +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/Unity-Simulation-Timer/package.json + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util.meta new file mode 100644 index 0000000..624d08c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ead20b35ad40400f930ea8975fdd0f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md new file mode 100644 index 0000000..5763977 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 StinkySteak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md.meta new file mode 100644 index 0000000..cf4e2aa --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 449c20116b4724976879aadb9b214c25 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/LICENSE.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime.meta new file mode 100644 index 0000000..1129f12 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f29a212f88aa64554ace6bf12e0a6349 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config.meta new file mode 100644 index 0000000..a6bdc5b --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d1a99d840d22d84c9531fc200edf547 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset new file mode 100644 index 0000000..4af8553 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset @@ -0,0 +1,33 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b345aa8c625f48c42b128a3818160fa1, type: 3} + m_Name: DefaultBehaviourConfig + m_EditorClassIdentifier: + _moveBehaviour: + SinYMove: + _minSpeed: 0.5 + _maxSpeed: 1 + _minAmplitude: 0.5 + _maxAmplitude: 1 + _positionMaxRandom: 100 + SinAllAxisMove: + _minSpeed: 0.5 + _maxSpeed: 1 + _amplitude: 50 + WanderMove: + _circleRadius: 35 + _turnChance: 0.05 + _maxRadius: 2000 + _mass: 15 + _maxSpeed: 3 + _maxForce: 15 + _maxSpawnPositionRadius: 100 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset.meta new file mode 100644 index 0000000..2507a38 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: c840c2115726fe44a9fea3d815aa2a44 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Config/DefaultBehaviourConfig.asset + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs.meta new file mode 100644 index 0000000..2ce49f3 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 402a222d39bcec04c9a4a579f7f34d00 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab new file mode 100644 index 0000000..a65b42e --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab @@ -0,0 +1,1499 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2369874200235912250 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 411490606201437080} + - component: {fileID: 7183773101182214069} + - component: {fileID: 4873386953909733980} + - component: {fileID: 5121610408365958833} + m_Layer: 5 + m_Name: ButtonStressTest_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &411490606201437080 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2369874200235912250} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6208167603637657542} + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -550} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7183773101182214069 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2369874200235912250} + m_CullTransparentMesh: 1 +--- !u!114 &4873386953909733980 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2369874200235912250} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &5121610408365958833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2369874200235912250} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 4873386953909733980} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &2949295029646028804 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295029646028805} + - component: {fileID: 2949295029646028807} + - component: {fileID: 2949295029646028806} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295029646028805 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295029646028804} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2949295031425224393} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2949295029646028807 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295029646028804} + m_CullTransparentMesh: 1 +--- !u!114 &2949295029646028806 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295029646028804} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Start Server + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &2949295030053361131 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295030053361132} + - component: {fileID: 2949295030053361134} + - component: {fileID: 2949295030053361133} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295030053361132 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030053361131} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2949295031031992031} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2949295030053361134 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030053361131} + m_CullTransparentMesh: 1 +--- !u!114 &2949295030053361133 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030053361131} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Start Client + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &2949295030461725763 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295030461725767} + - component: {fileID: 2949295030461725766} + - component: {fileID: 2949295030461725765} + - component: {fileID: 2949295030461725764} + m_Layer: 5 + m_Name: BaseGUIGame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295030461725767 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030461725763} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 2949295030523368795} + - {fileID: 2949295031425224393} + - {fileID: 2949295031031992031} + - {fileID: 2785959335848331071} + - {fileID: 1602380986100675486} + - {fileID: 411490606201437080} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &2949295030461725766 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030461725763} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &2949295030461725765 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030461725763} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &2949295030461725764 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030461725763} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!1 &2949295030523368794 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295030523368795} + - component: {fileID: 2949295030523368797} + - component: {fileID: 2949295030523368796} + m_Layer: 5 + m_Name: TextNetStats + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295030523368795 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030523368794} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 307.58, y: -56} + m_SizeDelta: {x: 587.8942, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2949295030523368797 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030523368794} + m_CullTransparentMesh: 1 +--- !u!114 &2949295030523368796 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295030523368794} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Latency: 0' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &2949295031031992030 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295031031992031} + - component: {fileID: 2949295031031992018} + - component: {fileID: 2949295031031992017} + - component: {fileID: 2949295031031992016} + m_Layer: 5 + m_Name: ButtonClient + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295031031992031 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031031992030} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2949295030053361132} + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 129.5, y: -192.5} + m_SizeDelta: {x: 231.74377, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2949295031031992018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031031992030} + m_CullTransparentMesh: 1 +--- !u!114 &2949295031031992017 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031031992030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2949295031031992016 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031031992030} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2949295031031992017} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &2949295031425224392 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2949295031425224393} + - component: {fileID: 2949295031425224396} + - component: {fileID: 2949295031425224395} + - component: {fileID: 2949295031425224394} + m_Layer: 5 + m_Name: ButtonServer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2949295031425224393 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031425224392} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2949295029646028805} + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 129.5, y: -123} + m_SizeDelta: {x: 231.74377, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2949295031425224396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031425224392} + m_CullTransparentMesh: 1 +--- !u!114 &2949295031425224395 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031425224392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2949295031425224394 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2949295031425224392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2949295031425224395} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &3210129748349697552 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3610938996623157770} + - component: {fileID: 7299485511270184052} + - component: {fileID: 5951580322984392688} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3610938996623157770 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3210129748349697552} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1602380986100675486} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7299485511270184052 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3210129748349697552} + m_CullTransparentMesh: 1 +--- !u!114 &5951580322984392688 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3210129748349697552} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Start Test 2 (Move All Axis) + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &5299039946110257232 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6208167603637657542} + - component: {fileID: 9053057425770491513} + - component: {fileID: 8733179090585459397} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6208167603637657542 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5299039946110257232} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 411490606201437080} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &9053057425770491513 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5299039946110257232} + m_CullTransparentMesh: 1 +--- !u!114 &8733179090585459397 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5299039946110257232} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Start Test 2 (Move Wander) + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &6675347749783655533 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2785959335848331071} + - component: {fileID: 8090361398731076124} + - component: {fileID: 6565980762078260290} + - component: {fileID: 2548720917523317336} + m_Layer: 5 + m_Name: ButtonStressTest_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2785959335848331071 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6675347749783655533} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7246942540015437574} + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -387} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8090361398731076124 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6675347749783655533} + m_CullTransparentMesh: 1 +--- !u!114 &6565980762078260290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6675347749783655533} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2548720917523317336 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6675347749783655533} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6565980762078260290} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &7379672520417493790 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1602380986100675486} + - component: {fileID: 2086747720963671770} + - component: {fileID: 1784470430327977461} + - component: {fileID: 345396986829802617} + m_Layer: 5 + m_Name: ButtonStressTest_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1602380986100675486 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379672520417493790} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3610938996623157770} + m_Father: {fileID: 2949295030461725767} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -472} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2086747720963671770 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379672520417493790} + m_CullTransparentMesh: 1 +--- !u!114 &1784470430327977461 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379672520417493790} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &345396986829802617 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379672520417493790} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1784470430327977461} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &8128524951257606673 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7246942540015437574} + - component: {fileID: 8364524488952456275} + - component: {fileID: 182710037949680185} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7246942540015437574 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8128524951257606673} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2785959335848331071} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8364524488952456275 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8128524951257606673} + m_CullTransparentMesh: 1 +--- !u!114 &182710037949680185 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8128524951257606673} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Start Test 1 (Move Y) + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab.meta new file mode 100644 index 0000000..4931edb --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 6e6b75e5db829b54ba9287ce8d21b551 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Prefabs/BaseGUIGame.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts.meta new file mode 100644 index 0000000..c9bff46 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6298f96b397ee4445b27e31637dd916b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs new file mode 100644 index 0000000..dba6ae9 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + [CreateAssetMenu(fileName = nameof(BehaviourConfig), menuName = "Netcode Benchmark/Behaviour Config")] + public class BehaviourConfig : ScriptableObject + { + [SerializeField] private MoveBehaviour _moveBehaviour; + + [System.Serializable] + public struct MoveBehaviour + { + public SinMoveYWrapper SinYMove; + public SinRandomMoveWrapper SinAllAxisMove; + public WanderMoveWrapper WanderMove; + + public void CreateDefault() + { + SinYMove = SinMoveYWrapper.CreateDefault(); + SinAllAxisMove = SinRandomMoveWrapper.CreateDefault(); + WanderMove = WanderMoveWrapper.CreateDefault(); + } + } + + private void Reset() + { + _moveBehaviour.CreateDefault(); + } + + public void ApplyConfig(ref SinMoveYWrapper wrapper) + { + wrapper = _moveBehaviour.SinYMove; + } + + public void ApplyConfig(ref SinRandomMoveWrapper wrapper) + { + wrapper = _moveBehaviour.SinAllAxisMove; + } + + public void ApplyConfig(ref WanderMoveWrapper wrapper) + { + wrapper = _moveBehaviour.WanderMove; + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs.meta new file mode 100644 index 0000000..9629a1c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b345aa8c625f48c42b128a3818160fa1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourConfig.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper.meta new file mode 100644 index 0000000..d05c0f4 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6dc3396f4b66601449c872b2527234f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs new file mode 100644 index 0000000..f083bb4 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + public interface IMoveWrapper + { + void NetworkStart(Transform transform); + void NetworkUpdate(Transform transform); + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs.meta new file mode 100644 index 0000000..dc88021 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 62941d180260d4743b36d0b3214ca3b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/IMoveWrapper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs new file mode 100644 index 0000000..57db103 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + [System.Serializable] + public struct SinMoveYWrapper : IMoveWrapper + { + [SerializeField] private float _minSpeed; + [SerializeField] private float _maxSpeed; + [SerializeField] private float _minAmplitude; + [SerializeField] private float _maxAmplitude; + [SerializeField] private float _positionMaxRandom; + + private Vector3 _initialPosition; + + private float _speed; + private float _amplitude; + + public static SinMoveYWrapper CreateDefault() + { + SinMoveYWrapper wrapper = new SinMoveYWrapper(); + wrapper._minSpeed = 0.5f; + wrapper._maxSpeed = 1f; + wrapper._minAmplitude = 0.5f; + wrapper._maxAmplitude = 1f; + wrapper._positionMaxRandom = 5f; + + return wrapper; + } + + public void NetworkStart(Transform transform) + { + _speed = Random.Range(_minSpeed, _maxSpeed); + _amplitude = Random.Range(_minAmplitude, _maxAmplitude); + _initialPosition = RandomVector3.Get(_positionMaxRandom); + } + + public void NetworkUpdate(Transform transform) + { + float sin = Mathf.Sin(Time.time * _speed) * _amplitude; + + transform.position = _initialPosition + (Vector3.up * sin); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs.meta new file mode 100644 index 0000000..8c55061 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2a8c50aebdfe1ad42bfa887f78c8892f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinMoveYWrapper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs new file mode 100644 index 0000000..ae35c49 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + [System.Serializable] + public struct SinRandomMoveWrapper : IMoveWrapper + { + [SerializeField] private float _minSpeed; + [SerializeField] private float _maxSpeed; + [SerializeField] private float _amplitude; + + private Vector3 _targetPosition; + private Vector3 _initialPosition; + + private float _speed; + + public static SinRandomMoveWrapper CreateDefault() + { + SinRandomMoveWrapper wrapper = new SinRandomMoveWrapper(); + wrapper._minSpeed = 1f; + wrapper._maxSpeed = 1f; + wrapper._amplitude = 1f; + + return wrapper; + } + + public void NetworkStart(Transform transform) + { + _speed = Random.Range(_minSpeed, _maxSpeed); + _targetPosition = RandomVector3.Get(1f); + } + + public void NetworkUpdate(Transform transform) + { + float sin = Mathf.Sin(Time.time * _speed) * _amplitude; + + transform.position = _initialPosition + (_targetPosition * sin); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs.meta new file mode 100644 index 0000000..a6f6bf9 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3584eba3ddc985c409f283d204fea105 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/SinRandomMoveWrapper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs new file mode 100644 index 0000000..4a71e41 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs @@ -0,0 +1,86 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + [System.Serializable] + public struct WanderMoveWrapper : IMoveWrapper + { + [SerializeField] private float _circleRadius; + [SerializeField] private float _turnChance; + [SerializeField] private float _maxRadius; + + [SerializeField] private float _mass; + [SerializeField] private float _maxSpeed; + [SerializeField] private float _maxForce; + + [SerializeField] private float _maxSpawnPositionRadius; + + private Vector3 _velocity; + private Vector3 _wanderForce; + private Vector3 _target; + + public static WanderMoveWrapper CreateDefault() + { + WanderMoveWrapper data = new WanderMoveWrapper(); + data._circleRadius = 1; + data._turnChance = 0.05f; + data._maxRadius = 5; + data._mass = 15; + data._maxSpeed = 3; + data._maxForce = 15; + + return data; + } + + public void NetworkStart(Transform transform) + { + _velocity = Random.onUnitSphere; + _wanderForce = GetRandomWanderForce(); + transform.position = RandomVector3.Get(_maxSpawnPositionRadius); + } + + public void NetworkUpdate(Transform transform) + { + var desiredVelocity = GetWanderForce(transform); + desiredVelocity = desiredVelocity.normalized * _maxSpeed; + + var steeringForce = desiredVelocity - _velocity; + steeringForce = Vector3.ClampMagnitude(steeringForce, _maxForce); + steeringForce /= _mass; + + _velocity = Vector3.ClampMagnitude(_velocity + steeringForce, _maxSpeed); + transform.position += _velocity * Time.deltaTime; + transform.forward = _velocity.normalized; + + Debug.DrawRay(transform.position, _velocity.normalized * 2, Color.green); + Debug.DrawRay(transform.position, desiredVelocity.normalized * 2, Color.magenta); + } + + private Vector3 GetWanderForce(Transform transform) + { + if (transform.position.magnitude > _maxRadius) + { + var directionToCenter = (_target - transform.position).normalized; + _wanderForce = _velocity.normalized + directionToCenter; + } + else if (Random.value < _turnChance) + { + _wanderForce = GetRandomWanderForce(); + } + + return _wanderForce; + } + + private Vector3 GetRandomWanderForce() + { + var circleCenter = _velocity.normalized; + var randomPoint = Random.insideUnitCircle; + + var displacement = new Vector3(randomPoint.x, randomPoint.y) * _circleRadius; + displacement = Quaternion.LookRotation(_velocity) * displacement; + + var wanderForce = circleCenter + displacement; + return wanderForce; + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs.meta new file mode 100644 index 0000000..002f994 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 5e236bbe49894bf4f972fe81f2081c8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/BehaviourWrapper/WanderMoveWrapper.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs new file mode 100644 index 0000000..81d01fa --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +namespace StinkySteak.NetcodeBenchmark +{ + public static class RandomVector3 + { + public static Vector3 Get(float max) + { + float x = Random.Range(-max, max); + float y = Random.Range(-max, max); + float z = Random.Range(-max, max); + + return new Vector3(x, y, z); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs.meta new file mode 100644 index 0000000..f581d17 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 17d9458a0ed386d4281f9c5085b42118 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/RandomVector3.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI.meta new file mode 100644 index 0000000..c27c6cc --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae950d5124e344a46a2f1aa4dc532bc8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs new file mode 100644 index 0000000..2be0c8c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs @@ -0,0 +1,94 @@ +// using TMPro; // MIRROR CHANGE +using UnityEngine; +using UnityEngine.UI; + +namespace StinkySteak.NetcodeBenchmark +{ + public class BaseGUIGame : MonoBehaviour + { + // [SerializeField] private Button _buttonStartServer; // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + // [SerializeField] private Button _buttonStartClient; // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + + [Space] + // MIRROR CHANGE + protected string _textLatency = ""; // [SerializeField] protected TextMesh _textLatency; // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + [SerializeField] private float _updateLatencyTextInterval = 1f; + private SimulationTimer.SimulationTimer _timerUpdateLatencyText; + + [Header("Stress Test 1: Move Y")] + [SerializeField] protected StressTestEssential _test_1; + + [Header("Stress Test 2: Move All Axis")] + [SerializeField] protected StressTestEssential _test_2; + + [Header("Stress Test 3: Move Wander")] + [SerializeField] protected StressTestEssential _test_3; + + [System.Serializable] + public struct StressTestEssential + { + // public Button ButtonExecute; // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + public int SpawnCount; + public GameObject Prefab; + } + + private void Start() + { + Initialize(); + } + + // MIRROR CHANGE: OnGUI instead of Canvas + TextMeshPro + protected virtual void Initialize() + { + // _test_1.ButtonExecute.onClick.AddListener(StressTest_1); + // _test_2.ButtonExecute.onClick.AddListener(StressTest_2); + // _test_3.ButtonExecute.onClick.AddListener(StressTest_3); + // + // _buttonStartServer.onClick.AddListener(StartServer); + // _buttonStartClient.onClick.AddListener(StartClient); + } + protected virtual void OnCustomGUI() {} + protected virtual void OnGUI() + { + GUILayout.BeginArea(new Rect(100, 100, 300, 400)); + + if (GUILayout.Button("Stress Test 1")) + { + StressTest_1(); + } + if (GUILayout.Button("Stress Test 2")) + { + StressTest_2(); + } + if (GUILayout.Button("Stress Test 3")) + { + StressTest_3(); + } + + OnCustomGUI(); + + GUILayout.Label(_textLatency); + + GUILayout.EndArea(); + } + // END MIRROR CHANGE + + protected virtual void StartClient() { } + protected virtual void StartServer() { } + private void StressTest_1() => StressTest(_test_1); + private void StressTest_2() => StressTest(_test_2); + private void StressTest_3() => StressTest(_test_3); + protected virtual void StressTest(StressTestEssential stressTest) { } + + + private void LateUpdate() + { + if (!_timerUpdateLatencyText.IsExpiredOrNotRunning()) return; + + UpdateNetworkStats(); + _timerUpdateLatencyText = SimulationTimer.SimulationTimer.CreateFromSeconds(_updateLatencyTextInterval); + } + + protected virtual void UpdateNetworkStats() { } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs.meta new file mode 100644 index 0000000..6a2f346 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0f64aeea8d696ff4fbb80a37fad8ebd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Scripts/UI/BaseGUIGame.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders.meta new file mode 100644 index 0000000..24b337c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65744866da2028e4fab6871830543ca5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat new file mode 100644 index 0000000..83e037b --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Unlit + m_Shader: {fileID: 4800000, guid: 2126a83145dd7bc48959270850637c77, type: 3} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: [] + m_Ints: [] + m_Floats: + - __dirty: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat.meta new file mode 100644 index 0000000..f91ba6c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: aa7b0f2a00af4ef4bac3c70fb2c798eb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader new file mode 100644 index 0000000..24a1e03 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader @@ -0,0 +1,37 @@ +Shader "Unlit" +{ + Properties + { + _Color("Color", Color) = (1,1,1,1) + [HideInInspector] __dirty( "", Int ) = 1 + } + + SubShader + { + Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+0" "IsEmissive" = "true" } + Cull Back + CGPROGRAM + #pragma target 3.0 + #pragma surface surf Unlit keepalpha addshadow fullforwardshadows + struct Input + { + half filler; + }; + + uniform float4 _Color; + + inline half4 LightingUnlit( SurfaceOutput s, half3 lightDir, half atten ) + { + return half4 ( 0, 0, 0, s.Alpha ); + } + + void surf( Input i , inout SurfaceOutput o ) + { + o.Emission = _Color.rgb; + o.Alpha = 1; + } + + ENDCG + } + Fallback "Diffuse" +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader.meta new file mode 100644 index 0000000..ad48fc6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 2126a83145dd7bc48959270850637c77 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Dependencies/netcode-benchmarker-util/Runtime/Shaders/Unlit.shader + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md b/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md new file mode 100644 index 0000000..5763977 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 StinkySteak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md.meta new file mode 100644 index 0000000..9126249 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 47c281457363740d58cafc331b207e35 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/LICENSE.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity b/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity new file mode 100644 index 0000000..bd234ae --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity @@ -0,0 +1,337 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311924, g: 0.38073963, b: 0.3587269, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &711140055 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 711140058} + - component: {fileID: 711140057} + - component: {fileID: 711140056} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &711140056 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 711140055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &711140057 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 711140055} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &711140058 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 711140055} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -20} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1186661038 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1186661040} + - component: {fileID: 1186661039} + m_Layer: 0 + m_Name: GUIGame_OnGUI // MIRROR CHANGE + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1186661039 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1186661038} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 89b59180da8577947a00064507b6f488, type: 3} + m_Name: + m_EditorClassIdentifier: + _textLatency: {fileID: 0} + _updateLatencyTextInterval: 1 + _test_1: + SpawnCount: 500 + Prefab: {fileID: 2997158864174378348, guid: 296e7798207e69a40a871087348da0c3, + type: 3} + _test_2: + SpawnCount: 500 + Prefab: {fileID: 6859501204968983109, guid: a7278693f35741148b381178a112e24d, + type: 3} + _test_3: + SpawnCount: 500 + Prefab: {fileID: 6660102892434074099, guid: 9925ea7d66c38ac48a88a572a9236cbe, + type: 3} + _networkManagerPrefab: {fileID: 6902534888765376180, guid: 62d3b9c46c08c934ea2ac02811b3028d, + type: 3} +--- !u!4 &1186661040 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1186661038} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -8.328793, y: -9.683151, z: 3.160122} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity.meta new file mode 100644 index 0000000..6da03d6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Main.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs.meta new file mode 100644 index 0000000..c350c8a --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c9c530e587fbf14ab144ab380ea96e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab new file mode 100644 index 0000000..d497ec6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab @@ -0,0 +1,1371 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &26160577204317890 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2219424647726365400} + - component: {fileID: 5304290874441819302} + - component: {fileID: 8843868705633827842} + - component: {fileID: 5880742282479012113} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2219424647726365400 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 26160577204317890} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4245933560767390540} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5304290874441819302 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 26160577204317890} + m_CullTransparentMesh: 1 +--- !u!23 &8843868705633827842 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 26160577204317890} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &5880742282479012113 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 26160577204317890} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &305782033035927766 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782033035927767} + - component: {fileID: 305782033035927765} + - component: {fileID: 8449117569946328787} + - component: {fileID: 6525481569155002542} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782033035927767 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033035927766} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 305782034880601627} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &305782033035927765 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033035927766} + m_CullTransparentMesh: 1 +--- !u!23 &8449117569946328787 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033035927766} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &6525481569155002542 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033035927766} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &305782033509647673 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782033509647678} + - component: {fileID: 305782033509647676} + - component: {fileID: 1888322870153146678} + - component: {fileID: 7728953946781801900} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782033509647678 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033509647673} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 305782034420293133} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &305782033509647676 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033509647673} + m_CullTransparentMesh: 1 +--- !u!23 &1888322870153146678 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033509647673} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &7728953946781801900 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033509647673} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &305782033917095057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782033917095061} + - component: {fileID: 305782033917095060} + - component: {fileID: 305782033917095063} + - component: {fileID: 305782033917095062} + - component: {fileID: 305782033917095056} + m_Layer: 5 + m_Name: GUIGame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782033917095061 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033917095057} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 305782033979164041} + - {fileID: 305782034880601627} + - {fileID: 305782034420293133} + - {fileID: 754894270325954541} + - {fileID: 4245933560767390540} + - {fileID: 2982987764379036490} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &305782033917095060 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033917095057} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 25 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &305782033917095063 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033917095057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &305782033917095062 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033917095057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &305782033917095056 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033917095057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 89b59180da8577947a00064507b6f488, type: 3} + m_Name: + m_EditorClassIdentifier: + _updateLatencyTextInterval: 1 + _test_1: + SpawnCount: 500 + Prefab: {fileID: 2997158864174378348, guid: 296e7798207e69a40a871087348da0c3, + type: 3} + _test_2: + SpawnCount: 500 + Prefab: {fileID: 6859501204968983109, guid: a7278693f35741148b381178a112e24d, + type: 3} + _test_3: + SpawnCount: 500 + Prefab: {fileID: 6660102892434074099, guid: 9925ea7d66c38ac48a88a572a9236cbe, + type: 3} + _networkManagerPrefab: {fileID: 6902534888765376180, guid: 62d3b9c46c08c934ea2ac02811b3028d, + type: 3} +--- !u!1 &305782033979164040 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782033979164041} + - component: {fileID: 305782033979164047} + - component: {fileID: 3416211776764084377} + - component: {fileID: 4381727190632658528} + m_Layer: 5 + m_Name: TextNetStats + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782033979164041 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033979164040} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 305782033917095061} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 307.58, y: -56} + m_SizeDelta: {x: 587.8942, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &305782033979164047 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033979164040} + m_CullTransparentMesh: 1 +--- !u!23 &3416211776764084377 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033979164040} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &4381727190632658528 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782033979164040} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &305782034420293132 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782034420293133} + - component: {fileID: 305782034420293120} + - component: {fileID: 305782034420293123} + - component: {fileID: 305782034420293122} + m_Layer: 5 + m_Name: ButtonClient + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782034420293133 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034420293132} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 305782033509647678} + m_Father: {fileID: 305782033917095061} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 129.5, y: -192.5} + m_SizeDelta: {x: 231.74377, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &305782034420293120 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034420293132} + m_CullTransparentMesh: 1 +--- !u!114 &305782034420293123 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034420293132} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &305782034420293122 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034420293132} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 305782034420293123} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &305782034880601626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 305782034880601627} + - component: {fileID: 305782034880601630} + - component: {fileID: 305782034880601625} + - component: {fileID: 305782034880601624} + m_Layer: 5 + m_Name: ButtonServer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &305782034880601627 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034880601626} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 305782033035927767} + m_Father: {fileID: 305782033917095061} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 129.5, y: -123} + m_SizeDelta: {x: 231.74377, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &305782034880601630 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034880601626} + m_CullTransparentMesh: 1 +--- !u!114 &305782034880601625 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034880601626} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &305782034880601624 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 305782034880601626} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 305782034880601625} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &879089305853721832 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2982987764379036490} + - component: {fileID: 5720055880973881191} + - component: {fileID: 8030450895206341262} + - component: {fileID: 7765268506151843427} + m_Layer: 5 + m_Name: ButtonStressTest_3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2982987764379036490 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 879089305853721832} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8860705395979898644} + m_Father: {fileID: 305782033917095061} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -550} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5720055880973881191 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 879089305853721832} + m_CullTransparentMesh: 1 +--- !u!114 &8030450895206341262 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 879089305853721832} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &7765268506151843427 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 879089305853721832} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8030450895206341262} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &5384482273043125196 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4245933560767390540} + - component: {fileID: 3469397789870953992} + - component: {fileID: 3752603985690682663} + - component: {fileID: 2889977997276142763} + m_Layer: 5 + m_Name: ButtonStressTest_2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4245933560767390540 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5384482273043125196} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2219424647726365400} + m_Father: {fileID: 305782033917095061} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -472} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3469397789870953992 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5384482273043125196} + m_CullTransparentMesh: 1 +--- !u!114 &3752603985690682663 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5384482273043125196} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2889977997276142763 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5384482273043125196} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 3752603985690682663} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6637753311149046467 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5206747001158653908} + - component: {fileID: 6396406296622199937} + - component: {fileID: 909359763545739655} + - component: {fileID: 8216700259004515211} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5206747001158653908 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6637753311149046467} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 754894270325954541} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6396406296622199937 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6637753311149046467} + m_CullTransparentMesh: 1 +--- !u!23 &909359763545739655 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6637753311149046467} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &8216700259004515211 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6637753311149046467} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &7303048414112782466 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8860705395979898644} + - component: {fileID: 5868947693164756651} + - component: {fileID: 7856834735450024799} + - component: {fileID: 4387876598551861384} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8860705395979898644 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303048414112782466} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2982987764379036490} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5868947693164756651 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303048414112782466} + m_CullTransparentMesh: 1 +--- !u!23 &7856834735450024799 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303048414112782466} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &4387876598551861384 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303048414112782466} + m_Text: + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 0 + m_Alignment: 0 + m_TabSize: 4 + m_FontSize: 0 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 0} + m_Color: + serializedVersion: 2 + rgba: 4294967295 +--- !u!1 &8103034003946407103 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 754894270325954541} + - component: {fileID: 6671774728501863118} + - component: {fileID: 8633215357807819920} + - component: {fileID: 1121039224619405962} + m_Layer: 5 + m_Name: ButtonStressTest_1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &754894270325954541 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8103034003946407103} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5206747001158653908} + m_Father: {fileID: 305782033917095061} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 208.09924, y: -387} + m_SizeDelta: {x: 388.9423, y: 53.411133} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6671774728501863118 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8103034003946407103} + m_CullTransparentMesh: 1 +--- !u!114 &8633215357807819920 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8103034003946407103} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1121039224619405962 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8103034003946407103} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8633215357807819920} + m_OnClick: + m_PersistentCalls: + m_Calls: [] diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab.meta new file mode 100644 index 0000000..a04dfd3 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7c764c613d90a5e4eb9ae8c5f2483eca +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/GUIGame.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab new file mode 100644 index 0000000..b0a69f0 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab @@ -0,0 +1,111 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6902534888765376181 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6902534888765376183} + - component: {fileID: 6902534888765376180} + - component: {fileID: 6712455278405722842} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6902534888765376183 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6902534888765376181} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6902534888765376180 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6902534888765376181} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 20 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 6712455278405722842} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 388937345275023605, guid: fc40b1557a4729e4e9cfaad99e1097ff, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 +--- !u!114 &6712455278405722842 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6902534888765376181} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 25565 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab.meta new file mode 100644 index 0000000..ac68b27 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 62d3b9c46c08c934ea2ac02811b3028d +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/NetworkManager.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab new file mode 100644 index 0000000..c10e6e0 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &388937345275023605 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 388937345275023603} + - component: {fileID: 388937345275023604} + m_Layer: 0 + m_Name: PlayerDummy + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &388937345275023603 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388937345275023605} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &388937345275023604 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388937345275023605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 738695246 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab.meta new file mode 100644 index 0000000..8d293f0 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: fc40b1557a4729e4e9cfaad99e1097ff +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/PlayerDummy.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab new file mode 100644 index 0000000..1f74ca6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab @@ -0,0 +1,181 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6859501204968983109 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6859501204968983104} + - component: {fileID: 6859501204968983110} + - component: {fileID: 6859501204968983108} + - component: {fileID: 4164372541306329233} + m_Layer: 0 + m_Name: SphereMoveAllAxis + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6859501204968983104 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501204968983109} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6859501205988317068} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6859501204968983110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501204968983109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a33ff1aaf3c582459143cebb4ab7cf9, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + _config: {fileID: 11400000, guid: 7d859fe3222918f4e9b2fe25afa82ced, type: 2} +--- !u!114 &6859501204968983108 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501204968983109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1165019082 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &4164372541306329233 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501204968983109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 6859501204968983104} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!1 &6859501205988317069 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6859501205988317068} + - component: {fileID: 6859501205988317070} + - component: {fileID: 6859501205988317071} + m_Layer: 0 + m_Name: Visual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6859501205988317068 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501205988317069} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6859501204968983104} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6859501205988317070 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501205988317069} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6859501205988317071 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6859501205988317069} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1a4e2bf0f982f8341a79b69aaaadcf24, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab.meta new file mode 100644 index 0000000..36d2af8 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a7278693f35741148b381178a112e24d +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveAllAxis.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab new file mode 100644 index 0000000..69f9f26 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab @@ -0,0 +1,181 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6660102891578011557 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6660102891578011556} + - component: {fileID: 6660102891578011558} + - component: {fileID: 6660102891578011559} + m_Layer: 0 + m_Name: Visual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6660102891578011556 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102891578011557} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6660102892434074098} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6660102891578011558 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102891578011557} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6660102891578011559 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102891578011557} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1a4e2bf0f982f8341a79b69aaaadcf24, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &6660102892434074099 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6660102892434074098} + - component: {fileID: 6660102892434074109} + - component: {fileID: 6660102892434074110} + - component: {fileID: 3719388534151151571} + m_Layer: 0 + m_Name: SphereMoveWander + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6660102892434074098 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102892434074099} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6660102891578011556} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6660102892434074109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102892434074099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c98d55e9b7394a94d97efd119d590ecf, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + _config: {fileID: 11400000, guid: 7d859fe3222918f4e9b2fe25afa82ced, type: 2} +--- !u!114 &6660102892434074110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102892434074099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1525047303 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3719388534151151571 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6660102892434074099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 6660102892434074098} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab.meta new file mode 100644 index 0000000..65562a7 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9925ea7d66c38ac48a88a572a9236cbe +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveWander.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab new file mode 100644 index 0000000..6d601db --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab @@ -0,0 +1,181 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2997158862366106693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2997158862366106698} + - component: {fileID: 2997158862366106696} + - component: {fileID: 2997158862366106699} + m_Layer: 0 + m_Name: Visual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2997158862366106698 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158862366106693} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2997158864174378353} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2997158862366106696 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158862366106693} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2997158862366106699 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158862366106693} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1a4e2bf0f982f8341a79b69aaaadcf24, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2997158864174378348 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2997158864174378353} + - component: {fileID: 2997158864174378352} + - component: {fileID: 2997158864174378349} + - component: {fileID: 8058470056856446765} + m_Layer: 0 + m_Name: SphereMoveY + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2997158864174378353 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158864174378348} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2997158862366106698} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2997158864174378352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158864174378348} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 547d19395b603714c81fc33bfe0f37ca, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + _config: {fileID: 11400000, guid: 7d859fe3222918f4e9b2fe25afa82ced, type: 2} +--- !u!114 &2997158864174378349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158864174378348} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 420486911 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &8058470056856446765 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2997158864174378348} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2997158864174378353} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab.meta new file mode 100644 index 0000000..06d6600 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 296e7798207e69a40a871087348da0c3 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Prefabs/SphereMoveY.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts.meta new file mode 100644 index 0000000..ef336d0 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5f21760ef33f344a8be5294af5a64e9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs new file mode 100644 index 0000000..a58ccf2 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs @@ -0,0 +1,65 @@ +using Mirror; +using StinkySteak.NetcodeBenchmark; +using UnityEngine; + +namespace StinkySteak.MirrorBenchmark +{ + public class GUIGame : BaseGUIGame + { + [SerializeField] private NetworkManager _networkManagerPrefab; + private NetworkManager _networkManager; + + protected override void Initialize() + { + base.Initialize(); + _networkManager = Instantiate(_networkManagerPrefab); + RegisterPrefabs(new StressTestEssential[] { _test_1, _test_2, _test_3 }); + } + + private void RegisterPrefabs(StressTestEssential[] stressTestEssential) + { + for (int i = 0; i < stressTestEssential.Length; i++) + { + _networkManager.spawnPrefabs.Add(stressTestEssential[i].Prefab); + } + } + + // MIRROR CHANGE: OnGUI instead of Canvas + TextMeshPro + protected override void OnCustomGUI() + { + if (GUILayout.Button("Start Client")) + { + _networkManager.StartClient(); + } + if (GUILayout.Button("Start Server")) + { + _networkManager.StartServer(); + } + } + // END MIRROR CHANGE + + protected override void StressTest(StressTestEssential stressTest) + { + for (int i = 0; i < stressTest.SpawnCount; i++) + { + GameObject go = Instantiate(stressTest.Prefab); + NetworkServer.Spawn(go); + } + } + + protected override void UpdateNetworkStats() + { + if (_networkManager == null) return; + + if (!_networkManager.isNetworkActive) return; + + if (_networkManager.mode == NetworkManagerMode.ServerOnly) + { + _textLatency = ("Latency: 0ms (Server)"); // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + return; + } + + _textLatency = ($"Latency: {NetworkTime.rtt * 1_000}ms"); // MIRROR CHANGE: Canvas + TextMeshPro -> OnGUI + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs.meta new file mode 100644 index 0000000..7251f6a --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 89b59180da8577947a00064507b6f488 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/GUIGame.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs new file mode 100644 index 0000000..d731ba9 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs @@ -0,0 +1,27 @@ +using Mirror; +using StinkySteak.NetcodeBenchmark; +using UnityEngine; + +namespace StinkySteak.MirrorBenchmark +{ + public class SineMoveRandomBehaviour : NetworkBehaviour + { + [SerializeField] private BehaviourConfig _config; + private SinRandomMoveWrapper _wrapper; + + public override void OnStartServer() + { + if (isClient) return; + + _config.ApplyConfig(ref _wrapper); + _wrapper.NetworkStart(transform); + } + + private void FixedUpdate() + { + if (isClient) return; + + _wrapper.NetworkUpdate(transform); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs.meta new file mode 100644 index 0000000..d72e421 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1a33ff1aaf3c582459143cebb4ab7cf9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveRandomBehaviour.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs new file mode 100644 index 0000000..bafa962 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs @@ -0,0 +1,27 @@ +using Mirror; +using StinkySteak.NetcodeBenchmark; +using UnityEngine; + +namespace StinkySteak.MirrorBenchmark +{ + public class SineMoveYBehaviour : NetworkBehaviour + { + [SerializeField] private BehaviourConfig _config; + private SinMoveYWrapper _wrapper; + + public override void OnStartServer() + { + if (isClient) return; + + _config.ApplyConfig(ref _wrapper); + _wrapper.NetworkStart(transform); + } + + private void FixedUpdate() + { + if (isClient) return; + + _wrapper.NetworkUpdate(transform); + } + } +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs.meta new file mode 100644 index 0000000..5d9ee25 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 547d19395b603714c81fc33bfe0f37ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/SineMoveYBehaviour.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs new file mode 100644 index 0000000..8a03866 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs @@ -0,0 +1,27 @@ +using Mirror; +using StinkySteak.NetcodeBenchmark; +using UnityEngine; + +namespace StinkySteak.MirrorBenchmark +{ + public class WanderMoveBehaviour : NetworkBehaviour + { + [SerializeField] private BehaviourConfig _config; + private WanderMoveWrapper _wrapper; + + public override void OnStartServer() + { + if (isClient) return; + + _config.ApplyConfig(ref _wrapper); + _wrapper.NetworkStart(transform); + } + + private void FixedUpdate() + { + if (isClient) return; + + _wrapper.NetworkUpdate(transform); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs.meta new file mode 100644 index 0000000..3c2c3d0 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c98d55e9b7394a94d97efd119d590ecf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Scripts/WanderMoveBehaviour.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders.meta new file mode 100644 index 0000000..5b954d6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45924815aac5c0b4a8cffc45aada4031 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat new file mode 100644 index 0000000..83e037b --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat @@ -0,0 +1,28 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Unlit + m_Shader: {fileID: 4800000, guid: 2126a83145dd7bc48959270850637c77, type: 3} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: [] + m_Ints: [] + m_Floats: + - __dirty: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat.meta new file mode 100644 index 0000000..d192fa6 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 1a4e2bf0f982f8341a79b69aaaadcf24 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader new file mode 100644 index 0000000..24a1e03 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader @@ -0,0 +1,37 @@ +Shader "Unlit" +{ + Properties + { + _Color("Color", Color) = (1,1,1,1) + [HideInInspector] __dirty( "", Int ) = 1 + } + + SubShader + { + Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+0" "IsEmissive" = "true" } + Cull Back + CGPROGRAM + #pragma target 3.0 + #pragma surface surf Unlit keepalpha addshadow fullforwardshadows + struct Input + { + half filler; + }; + + uniform float4 _Color; + + inline half4 LightingUnlit( SurfaceOutput s, half3 lightDir, half atten ) + { + return half4 ( 0, 0, 0, s.Alpha ); + } + + void surf( Input i , inout SurfaceOutput o ) + { + o.Emission = _Color.rgb; + o.Alpha = 1; + } + + ENDCG + } + Fallback "Diffuse" +} diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader.meta new file mode 100644 index 0000000..9bf36d4 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: a94f61d08bdef7544b7280e244eb54f5 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/Shaders/Unlit.shader + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt b/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt new file mode 100644 index 0000000..8403967 --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt @@ -0,0 +1,10 @@ +Steak's Netcode Benchmark from: +https://github.com/StinkySteak/unity-netcode-benchmark/ + +Results: +https://colorful-flyaway-e2f.notion.site/Netcode-Benchmark-f431976feb014ce48e030786f116e403?pvs=4 + +=> Copied into Mirror Examples so we can iterate on bandwidth improvements more quickly. +=> Also copied a few dependencies from: + https://github.com/StinkySteak/unity-netcode-benchmark/blob/master/mirror/Packages/manifest.json +=> replaced TextMeshPro with TextMesh \ No newline at end of file diff --git a/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt.meta b/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt.meta new file mode 100644 index 0000000..dc45b5c --- /dev/null +++ b/Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7c012b909308747838d0ae38e292f53a +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BenchmarkStinkySteak/_Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards.meta b/Assets/Mirror/Examples/Billiards.meta new file mode 100644 index 0000000..95ba6bf --- /dev/null +++ b/Assets/Mirror/Examples/Billiards.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f3d05950eb5fe40cfae60f94899382cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Billiards/Ball.meta b/Assets/Mirror/Examples/Billiards/Ball.meta new file mode 100644 index 0000000..58ff2c3 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf55a652f65984443942100efad31ffe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial b/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial new file mode 100644 index 0000000..26d5e52 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Ball + dynamicFriction: 0.6 + staticFriction: 0.6 + bounciness: 0.8 + frictionCombine: 0 + bounceCombine: 0 diff --git a/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial.meta b/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial.meta new file mode 100644 index 0000000..b321360 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: b70c4b1c659c647859a8491848d4b145 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/Ball.physicMaterial + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/Red.mat b/Assets/Mirror/Examples/Billiards/Ball/Red.mat new file mode 100644 index 0000000..77a2272 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Red.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.92 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0.2971698, b: 0.2971698, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Ball/Red.mat.meta b/Assets/Mirror/Examples/Billiards/Ball/Red.mat.meta new file mode 100644 index 0000000..26766d2 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Red.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 4260669eb9d994f8c96cd5be23e52164 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/Red.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/Red.prefab b/Assets/Mirror/Examples/Billiards/Ball/Red.prefab new file mode 100644 index 0000000..1fe4451 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Red.prefab @@ -0,0 +1,181 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3429911415116987808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3429911415116987812} + - component: {fileID: 3429911415116987813} + - component: {fileID: 3429911415116987810} + - component: {fileID: 6723567693459418947} + - component: {fileID: 3429911415116987811} + - component: {fileID: -177125271246800426} + - component: {fileID: 5308121378143249733} + - component: {fileID: -4867038537898682568} + m_Layer: 0 + m_Name: Red + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3429911415116987812 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3429911415116987813 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3429911415116987810 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &6723567693459418947 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2811417777 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!135 &3429911415116987811 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Material: {fileID: 13400000, guid: b70c4b1c659c647859a8491848d4b145, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &-177125271246800426 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + serializedVersion: 2 + m_Mass: 0.5 + m_Drag: 0.5 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 4 + m_CollisionDetection: 2 +--- !u!114 &5308121378143249733 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4662d0882e1d446089fb4f73bfcaa224, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 +--- !u!114 &-4867038537898682568 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b20dc110904e47f8a154cdcf6433eae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 3429911415116987812} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 0 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + sendIntervalMultiplier: 1 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 diff --git a/Assets/Mirror/Examples/Billiards/Ball/Red.prefab.meta b/Assets/Mirror/Examples/Billiards/Ball/Red.prefab.meta new file mode 100644 index 0000000..704664b --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/Red.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d07e00a439ecd46e79554ec89f65317b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/Red.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs b/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs new file mode 100644 index 0000000..cca9624 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace Mirror.Examples.Billiards +{ + public class RedBall : NetworkBehaviour + { + // destroy when entering a pocket. + // there's only one trigger in the scene (the pocket). + [ServerCallback] + void OnTriggerEnter(Collider other) + { + NetworkServer.Destroy(gameObject); + } + } +} diff --git a/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs.meta b/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs.meta new file mode 100644 index 0000000..a849e91 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/RedBall.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4662d0882e1d446089fb4f73bfcaa224 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/RedBall.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/White.mat b/Assets/Mirror/Examples/Billiards/Ball/White.mat new file mode 100644 index 0000000..00e46c5 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/White.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.93 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Ball/White.mat.meta b/Assets/Mirror/Examples/Billiards/Ball/White.mat.meta new file mode 100644 index 0000000..c77f265 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/White.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: e88ccd07dc10d443b808d53676994410 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/White.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/White.prefab b/Assets/Mirror/Examples/Billiards/Ball/White.prefab new file mode 100644 index 0000000..0ab9070 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/White.prefab @@ -0,0 +1,314 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &982362981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 982362983} + - component: {fileID: 982362982} + m_Layer: 0 + m_Name: DragIndicator - Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &982362983 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 982362981} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 13} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3429911415116987812} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!120 &982362982 +LineRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 982362981} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10306, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Positions: + - {x: 0, y: 0, z: 0} + - {x: 0, y: 0, z: 1} + m_Parameters: + serializedVersion: 3 + widthMultiplier: 0.1 + widthCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + colorGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 0} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 31418 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + numCornerVertices: 0 + numCapVertices: 0 + alignment: 0 + textureMode: 0 + shadowBias: 0.5 + generateLightingData: 0 + m_UseWorldSpace: 1 + m_Loop: 0 +--- !u!1 &3429911415116987808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3429911415116987812} + - component: {fileID: 3429911415116987813} + - component: {fileID: 3429911415116987810} + - component: {fileID: -1560774411725421365} + - component: {fileID: 3429911415116987811} + - component: {fileID: 1848203816128897140} + - component: {fileID: 6607303410184343467} + - component: {fileID: -2991986576794647411} + m_Layer: 0 + m_Name: White + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3429911415116987812 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 982362983} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3429911415116987813 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3429911415116987810 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: e88ccd07dc10d443b808d53676994410, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &-1560774411725421365 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3439363140 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!135 &3429911415116987811 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Material: {fileID: 13400000, guid: b70c4b1c659c647859a8491848d4b145, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1848203816128897140 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + serializedVersion: 2 + m_Mass: 0.5 + m_Drag: 0.5 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 4 + m_CollisionDetection: 2 +--- !u!114 &6607303410184343467 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 22982698a2c944cf39e961e49e9cd00c, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + dragIndicator: {fileID: 982362982} + rigidBody: {fileID: 1848203816128897140} + forceMultiplier: 2 + maxForce: 40 +--- !u!114 &-2991986576794647411 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b20dc110904e47f8a154cdcf6433eae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 3429911415116987812} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 0 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + sendIntervalMultiplier: 1 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 diff --git a/Assets/Mirror/Examples/Billiards/Ball/White.prefab.meta b/Assets/Mirror/Examples/Billiards/Ball/White.prefab.meta new file mode 100644 index 0000000..bbc5223 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/White.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0100f0c90700741b496ccbc2fe54c196 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/White.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs b/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs new file mode 100644 index 0000000..7845640 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs @@ -0,0 +1,107 @@ +using System; +using Mirror; +using UnityEngine; + +namespace Mirror.Examples.Billiards +{ + public class WhiteBall : NetworkBehaviour + { + public LineRenderer dragIndicator; + public Rigidbody rigidBody; + public float forceMultiplier = 2; + public float maxForce = 40; + + // remember start position to reset to after entering a pocket + Vector3 startPosition; + + // cast mouse position on screen to world position + bool MouseToWorld(out Vector3 position) + { + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + Plane plane = new Plane(Vector3.up, transform.position); + if (plane.Raycast(ray, out float distance)) + { + position = ray.GetPoint(distance); + return true; + } + position = default; + return false; + } + + void Awake() + { + startPosition = transform.position; + } + + [ClientCallback] + void OnMouseDown() + { + // enable drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, transform.position); + dragIndicator.gameObject.SetActive(true); + } + + [ClientCallback] + void OnMouseDrag() + { + // cast mouse position to world + if (!MouseToWorld(out Vector3 current)) return; + + // drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, current); + } + + // all players can apply force to the white ball. + // (this is not cheat safe) + [Command(requiresAuthority = false)] + void CmdApplyForce(Vector3 force) + { + // AddForce has different force modes, see this excellent diagram: + // https://www.reddit.com/r/Unity3D/comments/psukm1/know_the_difference_between_forcemodes_a_little/ + // when applying a one-time force to the ball, we need 'Impulse'. + rigidBody.AddForce(force, ForceMode.Impulse); + } + + [ClientCallback] + void OnMouseUp() + { + // cast mouse position to world + if (!MouseToWorld(out Vector3 current)) return; + + // calculate delta from ball to mouse + // ball may have moved since we started dragging, + // so always use current ball position here. + Vector3 from = transform.position; + + // debug drawing: only works if Gizmos are enabled! + Debug.DrawLine(from, current, Color.white, 2); + + // calculate pending force delta + Vector3 delta = from - current; + Vector3 force = delta * forceMultiplier; + + // there should be a maximum allowed force + force = Vector3.ClampMagnitude(force, maxForce); + + // apply force to rigidbody. + // it will take a round trip to show the effect. + // the goal for prediction will be to show it immediately. + CmdApplyForce(force); + + // disable drag indicator + dragIndicator.gameObject.SetActive(false); + } + + // reset position when entering a pocket. + // there's only one trigger in the scene (the pocket). + [ServerCallback] + void OnTriggerEnter(Collider other) + { + rigidBody.position = startPosition; + rigidBody.Sleep(); // reset forces + GetComponent().RpcTeleport(startPosition); + } + } +} diff --git a/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs.meta b/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs.meta new file mode 100644 index 0000000..3733463 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 22982698a2c944cf39e961e49e9cd00c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Ball/WhiteBall.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity b/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity new file mode 100644 index 0000000..d0c60b6 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity @@ -0,0 +1,1445 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.27059805, y: 0.6532815, z: -0.27059805, w: 0.6532815} + m_LocalPosition: {x: -30, y: 25, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 90, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!1001 &250045978 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 14 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 3968159719 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &582272032 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 12 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 2421286814 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1065868373 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 15 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: -2 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 4244123176 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1212703607 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 1265163748 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1224511671 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 14 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 113636724 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1261449042 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 16 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 548843218 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + - component: {fileID: 1282001523} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 120 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001523} + networkAddress: localhost + maxConnections: 2 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 7529115942715260948, guid: 2a61e2175dfa740fdbd5b75afe107cd7, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} + - {fileID: 3429911415116987808, guid: 0100f0c90700741b496ccbc2fe54c196, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 1 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bc654f29862fc2643b948f772ebb9e68, type: 3} + m_Name: + m_EditorClassIdentifier: + color: {r: 1, g: 1, b: 1, a: 1} + padding: 2 + width: 180 + height: 25 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 96b149f511061407fb54895c057b7736, type: 3} + m_Name: + m_EditorClassIdentifier: + wrap: {fileID: 1282001521} + latency: 50 + jitter: 0.02 + jitterSpeed: 1 + unreliableLoss: 2 + unreliableScramble: 2 +--- !u!1001 &1633978772 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 13 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 1812929624 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1783527201 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 11 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 3532386042 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &1872597095 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: -1560774411725421365, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: sceneId + value: 1318684626 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987808, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_Name + value: White + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalPosition.z + value: -13 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 0100f0c90700741b496ccbc2fe54c196, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 0100f0c90700741b496ccbc2fe54c196, type: 3} +--- !u!1001 &1976225798 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 4036781605 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0, y: 0.9063079, z: -0.42261827, w: 0} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: 180, z: 0} +--- !u!1001 &2094108392 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Name + value: Red + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987810, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 4260669eb9d994f8c96cd5be23e52164, type: 2} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_RootOrder + value: 12 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalPosition.z + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: d07e00a439ecd46e79554ec89f65317b, + type: 3} + propertyPath: sceneId + value: 434333461 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: d07e00a439ecd46e79554ec89f65317b, type: 3} +--- !u!1001 &3539222711505105259 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.y + value: -9.79 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4634620164816052983, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_Name + value: Billiard Table + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: dc0a91834ded843aba24753233b8c029, type: 3} diff --git a/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity.meta b/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity.meta new file mode 100644 index 0000000..3f9d16d --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/MirrorBilliards.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 72a58a2e3a00b473795104a0379c5b02 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/MirrorBilliards.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Player.prefab b/Assets/Mirror/Examples/Billiards/Player.prefab new file mode 100644 index 0000000..fca33e5 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Player.prefab @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7529115942715260948 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1534822232247476853} + - component: {fileID: 1279227879756014839} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1534822232247476853 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7529115942715260948} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1279227879756014839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7529115942715260948} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3231422159 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 diff --git a/Assets/Mirror/Examples/Billiards/Player.prefab.meta b/Assets/Mirror/Examples/Billiards/Player.prefab.meta new file mode 100644 index 0000000..5203512 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2a61e2175dfa740fdbd5b75afe107cd7 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table.meta b/Assets/Mirror/Examples/Billiards/Table.meta new file mode 100644 index 0000000..44cb41c --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec5252e0dcaa64aff9b3a77600e2654c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab b/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab new file mode 100644 index 0000000..1df927a --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab @@ -0,0 +1,468 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3539222710066621743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3539222710066621742} + - component: {fileID: 3539222710066621731} + - component: {fileID: 3539222710066621740} + - component: {fileID: 3539222710066621729} + - component: {fileID: 3539222710066621730} + - component: {fileID: 3539222710066621728} + - component: {fileID: 3539222710066621735} + - component: {fileID: 3539222710066621734} + - component: {fileID: 3539222710066621732} + - component: {fileID: 3539222710066621733} + - component: {fileID: 4431155707644151673} + m_Layer: 0 + m_Name: PocketsCollider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3539222710066621742 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 1.52, z: -0} + m_LocalScale: {x: 2.6907747, y: 3.8628998, z: 1} + m_Children: [] + m_Father: {fileID: 3699661344160954761} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!33 &3539222710066621731 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3539222710066621740 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 345f064ee294143f9ba2aabdef269c2e, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!136 &3539222710066621729 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: -0.47, y: 0.48, z: 0} +--- !u!136 &3539222710066621730 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: 0.47, y: 0.48, z: 0} +--- !u!136 &3539222710066621728 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: 0.47, y: -0.48, z: 0} +--- !u!136 &3539222710066621735 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: -0.47, y: -0.48, z: 0} +--- !u!136 &3539222710066621734 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: 0.47, y: 0.48, z: 0} +--- !u!136 &3539222710066621732 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: 0.47, y: 0, z: 0} +--- !u!136 &3539222710066621733 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + m_Radius: 0.025 + m_Height: 1 + m_Direction: 2 + m_Center: {x: -0.47, y: 0, z: 0} +--- !u!114 &4431155707644151673 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222710066621743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f17c923d118b941fb90a834d87e9ff27, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &3539222711229660005 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3539222711229660004} + - component: {fileID: 3539222711229660027} + m_Layer: 0 + m_Name: FeltCollider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3539222711229660004 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222711229660005} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0.07, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3699661344160954761} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &3539222711229660027 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3539222711229660005} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 3.108116, y: 0.010857582, z: 4.301286} + m_Center: {x: 0, y: 1.4526881, z: 0} +--- !u!1 &4634620164816052983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3699661344160954761} + - component: {fileID: 4634620164816052931} + - component: {fileID: 4634620164816052940} + - component: {fileID: 4634620164816052982} + - component: {fileID: 4634620164816052981} + - component: {fileID: 4634620164816052980} + - component: {fileID: 4634620164816052939} + - component: {fileID: 4634620164816052938} + - component: {fileID: 4634620164816052937} + - component: {fileID: 4634620164816052936} + - component: {fileID: 4634620164816052943} + - component: {fileID: 4634620164816052942} + - component: {fileID: 4634620164816052941} + m_Layer: 0 + m_Name: Billiard Table + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3699661344160954761 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -9.79, z: 0} + m_LocalScale: {x: 10, y: 6, z: 10} + m_Children: + - {fileID: 3539222710066621742} + - {fileID: 3539222711229660004} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &4634620164816052931 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Mesh: {fileID: -2432090755550338912, guid: 25f03344dfdd844f88e89487c558fe35, type: 3} +--- !u!23 &4634620164816052940 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 7cfca2b6fd3df4580a0f098abfaf0c64, type: 2} + - {fileID: 2100000, guid: 658caa508b3164eeca5e3847394e87a1, type: 2} + - {fileID: 2100000, guid: d271ebc46b0f74b6fbf2eaab8586fb52, type: 2} + - {fileID: 2100000, guid: a5c5ac95f6b544173994adfaae202203, type: 2} + - {fileID: 2100000, guid: 963c1008ac3af4b1db863a7f7a858eac, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!65 &4634620164816052982 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.27664548, y: 0.35404286, z: 1.6448396} + m_Center: {x: 1.4157387, y: 1.5564016, z: 0.9292537} +--- !u!65 &4634620164816052981 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.24856225, y: 0.3767918, z: 1.6358687} + m_Center: {x: 1.4297806, y: 1.5450258, z: -0.91790134} +--- !u!65 &4634620164816052980 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.27990246, y: 0.26308474, z: 1.6164124} + m_Center: {x: -1.4141101, y: 1.6018808, z: 0.9198937} +--- !u!65 &4634620164816052939 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.27038383, y: 0.26613903, z: 1.6229101} + m_Center: {x: -1.4188734, y: 1.6003541, z: -0.9162423} +--- !u!65 &4634620164816052938 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2.2766645, y: 0.39401436, z: 0.26005593} + m_Center: {x: -0.0048750876, y: 1.5364149, z: -2.020621} +--- !u!65 &4634620164816052937 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 2.2623913, y: 0.27035016, z: 0.26550943} + m_Center: {x: -0.00041542054, y: 1.5982517, z: 2.0178926} +--- !u!65 &4634620164816052936 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.20316009, y: 0.27418074, z: 4.301286} + m_Center: {x: -1.4524853, y: 1.596332, z: 0} +--- !u!65 &4634620164816052943 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.19880867, y: 0.36284417, z: 4.301286} + m_Center: {x: 1.45466, y: 1.5520005, z: 0} +--- !u!65 &4634620164816052942 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 3.108116, y: 0.3710909, z: 0.19581757} + m_Center: {x: 0, y: 1.5478768, z: 2.0527387} +--- !u!65 &4634620164816052941 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4634620164816052983} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 3.108116, y: 0.3668445, z: 0.19877319} + m_Center: {x: 0, y: 1.5500016, z: -2.051263} diff --git a/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab.meta b/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab.meta new file mode 100644 index 0000000..679aa54 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: dc0a91834ded843aba24753233b8c029 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Billiard Table.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj b/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj new file mode 100644 index 0000000..3cce14e --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj @@ -0,0 +1,4468 @@ +# Blender v2.82 (sub 7) OBJ File: 'BilliardTable.blend' +# www.blender.org +mtllib BilliardTable.mtl +o Table_Plane +v -1.239295 0.911771 0.932339 +v -1.239295 0.911771 -0.932339 +v 1.239295 0.911771 0.932339 +v 1.239295 0.911771 -0.932339 +v -1.321964 1.493954 -1.749153 +v -1.321964 1.493954 -1.920233 +v -1.150884 1.493954 -1.749153 +v -1.150884 1.493954 -1.920233 +v -1.321964 1.600048 -1.749153 +v -1.321964 1.600048 -1.920233 +v -1.150884 1.600048 -1.920233 +v -1.346022 1.493954 -1.881473 +v -1.354041 1.493954 -1.834693 +v -1.346022 1.493954 -1.787914 +v -1.321964 1.634035 -1.749153 +v -1.321964 1.671146 -1.749153 +v -1.321964 1.710339 -1.749153 +v -1.321964 1.569880 -1.920233 +v -1.321964 1.542836 -1.920233 +v -1.321964 1.517874 -1.920233 +v -1.189644 1.493954 -1.944292 +v -1.236424 1.493954 -1.952311 +v -1.283203 1.493954 -1.944292 +v -1.150884 1.569880 -1.920233 +v -1.150884 1.542836 -1.920233 +v -1.150884 1.517874 -1.920233 +v -1.126825 1.493954 -1.787914 +v -1.118806 1.493954 -1.834693 +v -1.126825 1.493954 -1.881473 +v -1.150884 1.542836 -1.749153 +v -1.150884 1.517874 -1.749153 +v -1.283203 1.493954 -1.725095 +v -1.236424 1.493954 -1.717076 +v -1.189644 1.493954 -1.725095 +v -1.321964 1.517874 -1.749153 +v -1.321964 1.542836 -1.749153 +v -1.321964 1.569880 -1.749153 +v -1.321964 1.710339 -1.920233 +v -1.321964 1.671146 -1.920233 +v -1.321964 1.634035 -1.920233 +v -1.150884 1.710339 -1.920233 +v -1.150884 1.671146 -1.920233 +v -1.150884 1.634035 -1.920233 +v -1.283203 1.600048 -1.725095 +v -1.283203 1.600048 -1.944292 +v -1.236424 1.600048 -1.952311 +v -1.189644 1.600048 -1.944292 +v -1.346022 1.600048 -1.787914 +v -1.354041 1.600048 -1.834693 +v -1.346022 1.600048 -1.881473 +v -1.346022 1.634035 -1.787914 +v -1.346022 1.671146 -1.787914 +v -1.346022 1.710339 -1.787914 +v -1.354041 1.634035 -1.834693 +v -1.354041 1.671146 -1.834693 +v -1.354041 1.710339 -1.834693 +v -1.346022 1.634035 -1.881473 +v -1.346022 1.671146 -1.881473 +v -1.346022 1.710339 -1.881473 +v -1.283203 1.634035 -1.944292 +v -1.283203 1.671146 -1.944292 +v -1.283203 1.710339 -1.944292 +v -1.236424 1.634035 -1.952311 +v -1.236424 1.671146 -1.952311 +v -1.236424 1.710339 -1.952311 +v -1.189644 1.634035 -1.944292 +v -1.189644 1.671146 -1.944292 +v -1.189644 1.710339 -1.944292 +v -1.283203 1.634035 -1.725095 +v -1.283203 1.671146 -1.725095 +v -1.283203 1.710339 -1.725095 +v -1.291668 1.493954 -1.889938 +v -1.236424 1.493954 -1.893502 +v -1.181179 1.493954 -1.889938 +v -1.295233 1.493954 -1.834693 +v -1.236424 1.493954 -1.834693 +v -1.177615 1.493954 -1.834693 +v -1.291668 1.493954 -1.779449 +v -1.236424 1.493954 -1.775885 +v -1.181179 1.493954 -1.779449 +v -1.189644 1.517874 -1.725095 +v -1.189644 1.542836 -1.725095 +v -1.236424 1.517874 -1.717076 +v -1.236424 1.542836 -1.717076 +v -1.283203 1.517874 -1.725095 +v -1.283203 1.542836 -1.725095 +v -1.283203 1.569880 -1.725095 +v -1.126825 1.517874 -1.881473 +v -1.126825 1.542836 -1.881473 +v -1.118806 1.517874 -1.834693 +v -1.118806 1.542836 -1.834693 +v -1.126825 1.517874 -1.787914 +v -1.126825 1.542836 -1.787914 +v -1.283203 1.517874 -1.944292 +v -1.283203 1.542836 -1.944292 +v -1.283203 1.569880 -1.944292 +v -1.236424 1.517874 -1.952311 +v -1.236424 1.542836 -1.952311 +v -1.236424 1.569880 -1.952311 +v -1.189644 1.517874 -1.944292 +v -1.189644 1.542836 -1.944292 +v -1.189644 1.569880 -1.944292 +v -1.346022 1.517874 -1.787914 +v -1.346022 1.542836 -1.787914 +v -1.346022 1.569880 -1.787914 +v -1.354041 1.517874 -1.834693 +v -1.354041 1.542836 -1.834693 +v -1.354041 1.569880 -1.834693 +v -1.346022 1.517874 -1.881473 +v -1.346022 1.542836 -1.881473 +v -1.346022 1.569880 -1.881473 +v 1.148006 1.493954 -1.749153 +v 1.148006 1.493954 -1.920233 +v 1.319087 1.493954 -1.749153 +v 1.319087 1.493954 -1.920233 +v 1.148006 1.600048 -1.920233 +v 1.319087 1.600048 -1.920233 +v 1.319087 1.600048 -1.749153 +v 1.123948 1.493954 -1.881473 +v 1.115929 1.493954 -1.834693 +v 1.123948 1.493954 -1.787914 +v 1.148006 1.569880 -1.920233 +v 1.148006 1.542836 -1.920233 +v 1.148006 1.517874 -1.920233 +v 1.280326 1.493954 -1.944292 +v 1.233546 1.493954 -1.952311 +v 1.186767 1.493954 -1.944292 +v 1.319087 1.569880 -1.920233 +v 1.319087 1.542836 -1.920233 +v 1.319087 1.517874 -1.920233 +v 1.343145 1.493954 -1.787914 +v 1.351164 1.493954 -1.834693 +v 1.343145 1.493954 -1.881473 +v 1.319087 1.569880 -1.749153 +v 1.319087 1.542836 -1.749153 +v 1.319087 1.517874 -1.749153 +v 1.186767 1.493954 -1.725095 +v 1.233546 1.493954 -1.717076 +v 1.280326 1.493954 -1.725095 +v 1.148006 1.517874 -1.749153 +v 1.148006 1.542836 -1.749153 +v 1.148006 1.710339 -1.920233 +v 1.148006 1.671146 -1.920233 +v 1.148006 1.634035 -1.920233 +v 1.319087 1.710339 -1.920233 +v 1.319087 1.671146 -1.920233 +v 1.319087 1.634035 -1.920233 +v 1.319087 1.710339 -1.749153 +v 1.319087 1.671146 -1.749153 +v 1.319087 1.634035 -1.749153 +v 1.343145 1.600048 -1.881473 +v 1.351164 1.600048 -1.834693 +v 1.343145 1.600048 -1.787914 +v 1.186767 1.600048 -1.944292 +v 1.233546 1.600048 -1.952311 +v 1.280326 1.600048 -1.944292 +v 1.186767 1.634035 -1.944292 +v 1.186767 1.671146 -1.944292 +v 1.186767 1.710339 -1.944292 +v 1.233546 1.634035 -1.952311 +v 1.233546 1.671146 -1.952311 +v 1.233546 1.710339 -1.952311 +v 1.280326 1.634035 -1.944292 +v 1.280326 1.671146 -1.944292 +v 1.280326 1.710339 -1.944292 +v 1.343145 1.634035 -1.881473 +v 1.343145 1.671146 -1.881473 +v 1.343145 1.710339 -1.881473 +v 1.351164 1.634035 -1.834693 +v 1.351164 1.671146 -1.834693 +v 1.351164 1.710339 -1.834693 +v 1.343145 1.634035 -1.787914 +v 1.343145 1.671146 -1.787914 +v 1.343145 1.710339 -1.787914 +v 1.178302 1.493954 -1.889938 +v 1.233546 1.493954 -1.893502 +v 1.288791 1.493954 -1.889938 +v 1.174738 1.493954 -1.834693 +v 1.233546 1.493954 -1.834693 +v 1.292356 1.493954 -1.834693 +v 1.178302 1.493954 -1.779449 +v 1.233546 1.493954 -1.775885 +v 1.288791 1.493954 -1.779449 +v 1.280326 1.517874 -1.725095 +v 1.280326 1.542836 -1.725095 +v 1.233546 1.517874 -1.717076 +v 1.233546 1.542836 -1.717076 +v 1.186767 1.517874 -1.725095 +v 1.186767 1.542836 -1.725095 +v 1.343145 1.517874 -1.881473 +v 1.343145 1.542836 -1.881473 +v 1.343145 1.569880 -1.881473 +v 1.351164 1.517874 -1.834693 +v 1.351164 1.542836 -1.834693 +v 1.351164 1.569880 -1.834693 +v 1.343145 1.517874 -1.787914 +v 1.343145 1.542836 -1.787914 +v 1.343145 1.569880 -1.787914 +v 1.186767 1.517874 -1.944292 +v 1.186767 1.542836 -1.944292 +v 1.186767 1.569880 -1.944292 +v 1.233546 1.517874 -1.952311 +v 1.233546 1.542836 -1.952311 +v 1.233546 1.569880 -1.952311 +v 1.280326 1.517874 -1.944292 +v 1.280326 1.542836 -1.944292 +v 1.280326 1.569880 -1.944292 +v 1.123948 1.517874 -1.787914 +v 1.123948 1.542836 -1.787914 +v 1.115929 1.517874 -1.834693 +v 1.115929 1.542836 -1.834693 +v 1.123948 1.517874 -1.881473 +v 1.123948 1.542836 -1.881473 +v -1.321964 1.493954 0.090386 +v -1.321964 1.493954 -0.080694 +v -1.150884 1.493954 0.090386 +v -1.150884 1.493954 -0.080694 +v -1.321964 1.600048 0.090386 +v -1.321964 1.600048 -0.080694 +v -1.346022 1.493954 -0.041933 +v -1.354041 1.493954 0.004846 +v -1.346022 1.493954 0.051626 +v -1.321964 1.634035 0.090386 +v -1.321964 1.671146 0.090386 +v -1.321964 1.710339 0.090386 +v -1.321964 1.569880 -0.080694 +v -1.321964 1.542836 -0.080694 +v -1.321964 1.517874 -0.080694 +v -1.189644 1.493954 -0.104752 +v -1.236424 1.493954 -0.112771 +v -1.283203 1.493954 -0.104752 +v -1.150884 1.542836 -0.080694 +v -1.150884 1.517874 -0.080694 +v -1.126825 1.493954 0.051626 +v -1.118806 1.493954 0.004846 +v -1.126825 1.493954 -0.041933 +v -1.150884 1.542836 0.090386 +v -1.150884 1.517874 0.090386 +v -1.283203 1.493954 0.114444 +v -1.236424 1.493954 0.122464 +v -1.189644 1.493954 0.114444 +v -1.321964 1.517874 0.090386 +v -1.321964 1.542836 0.090386 +v -1.321964 1.569880 0.090386 +v -1.321964 1.710339 -0.080694 +v -1.321964 1.671146 -0.080694 +v -1.321964 1.634035 -0.080694 +v -1.283203 1.600048 0.114444 +v -1.283203 1.600048 -0.104752 +v -1.346022 1.600048 0.051626 +v -1.354041 1.600048 0.004846 +v -1.346022 1.600048 -0.041933 +v -1.346022 1.634035 0.051626 +v -1.346022 1.671146 0.051626 +v -1.346022 1.710339 0.051626 +v -1.354041 1.634035 0.004846 +v -1.354041 1.671146 0.004846 +v -1.354041 1.710339 0.004846 +v -1.346022 1.634035 -0.041933 +v -1.346022 1.671146 -0.041933 +v -1.346022 1.710339 -0.041933 +v -1.283203 1.634035 -0.104752 +v -1.283203 1.671146 -0.104752 +v -1.283203 1.710339 -0.104752 +v -1.283203 1.634035 0.114444 +v -1.283203 1.671146 0.114444 +v -1.283203 1.710339 0.114444 +v -1.291668 1.493954 -0.050398 +v -1.236424 1.493954 -0.053962 +v -1.181179 1.493954 -0.050398 +v -1.295233 1.493954 0.004846 +v -1.236424 1.493954 0.004846 +v -1.177615 1.493954 0.004846 +v -1.291668 1.493954 0.060091 +v -1.236424 1.493954 0.063655 +v -1.181179 1.493954 0.060091 +v -1.189644 1.517874 0.114444 +v -1.189644 1.542836 0.114444 +v -1.236424 1.517874 0.122464 +v -1.236424 1.542836 0.122464 +v -1.283203 1.517874 0.114444 +v -1.283203 1.542836 0.114444 +v -1.283203 1.569880 0.114444 +v -1.126825 1.517874 -0.041933 +v -1.126825 1.542836 -0.041933 +v -1.118806 1.517874 0.004846 +v -1.118806 1.542836 0.004846 +v -1.126825 1.517874 0.051626 +v -1.126825 1.542836 0.051626 +v -1.283203 1.517874 -0.104752 +v -1.283203 1.542836 -0.104752 +v -1.283203 1.569880 -0.104752 +v -1.236424 1.517874 -0.112771 +v -1.236424 1.542836 -0.112771 +v -1.189644 1.517874 -0.104752 +v -1.189644 1.542836 -0.104752 +v -1.346022 1.517874 0.051626 +v -1.346022 1.542836 0.051626 +v -1.346022 1.569880 0.051626 +v -1.354041 1.517874 0.004846 +v -1.354041 1.542836 0.004846 +v -1.354041 1.569880 0.004846 +v -1.346022 1.517874 -0.041933 +v -1.346022 1.542836 -0.041933 +v -1.346022 1.569880 -0.041933 +v 1.148006 1.493954 0.090386 +v 1.148006 1.493954 -0.080694 +v 1.319087 1.493954 0.090386 +v 1.319087 1.493954 -0.080694 +v 1.319087 1.600048 -0.080694 +v 1.319087 1.600048 0.090386 +v 1.123948 1.493954 -0.041933 +v 1.115929 1.493954 0.004846 +v 1.123948 1.493954 0.051626 +v 1.148006 1.542836 -0.080694 +v 1.148006 1.517874 -0.080694 +v 1.280326 1.493954 -0.104752 +v 1.233546 1.493954 -0.112771 +v 1.186767 1.493954 -0.104752 +v 1.319087 1.569880 -0.080694 +v 1.319087 1.542836 -0.080694 +v 1.319087 1.517874 -0.080694 +v 1.343145 1.493954 0.051626 +v 1.351164 1.493954 0.004846 +v 1.343145 1.493954 -0.041933 +v 1.319087 1.569880 0.090386 +v 1.319087 1.542836 0.090386 +v 1.319087 1.517874 0.090386 +v 1.186767 1.493954 0.114444 +v 1.233546 1.493954 0.122464 +v 1.280326 1.493954 0.114444 +v 1.148006 1.517874 0.090386 +v 1.148006 1.542836 0.090386 +v 1.319087 1.710339 -0.080694 +v 1.319087 1.671146 -0.080694 +v 1.319087 1.634035 -0.080694 +v 1.319087 1.710339 0.090386 +v 1.319087 1.671146 0.090386 +v 1.319087 1.634035 0.090386 +v 1.343145 1.600048 -0.041933 +v 1.351164 1.600048 0.004846 +v 1.343145 1.600048 0.051626 +v 1.343145 1.634035 -0.041933 +v 1.343145 1.671146 -0.041933 +v 1.343145 1.710339 -0.041933 +v 1.351164 1.634035 0.004846 +v 1.351164 1.671146 0.004846 +v 1.351164 1.710339 0.004846 +v 1.343145 1.634035 0.051626 +v 1.343145 1.671146 0.051626 +v 1.343145 1.710339 0.051626 +v 1.178302 1.493954 -0.050398 +v 1.233546 1.493954 -0.053962 +v 1.288791 1.493954 -0.050398 +v 1.174738 1.493954 0.004846 +v 1.233546 1.493954 0.004846 +v 1.292356 1.493954 0.004846 +v 1.178302 1.493954 0.060091 +v 1.233546 1.493954 0.063655 +v 1.288791 1.493954 0.060091 +v 1.280326 1.517874 0.114444 +v 1.280326 1.542836 0.114444 +v 1.233546 1.517874 0.122464 +v 1.233546 1.542836 0.122464 +v 1.186767 1.517874 0.114444 +v 1.186767 1.542836 0.114444 +v 1.343145 1.517874 -0.041933 +v 1.343145 1.542836 -0.041933 +v 1.343145 1.569880 -0.041933 +v 1.351164 1.517874 0.004846 +v 1.351164 1.542836 0.004846 +v 1.351164 1.569880 0.004846 +v 1.343145 1.517874 0.051626 +v 1.343145 1.542836 0.051626 +v 1.343145 1.569880 0.051626 +v 1.186767 1.517874 -0.104752 +v 1.186767 1.542836 -0.104752 +v 1.233546 1.517874 -0.112771 +v 1.233546 1.542836 -0.112771 +v 1.280326 1.517874 -0.104752 +v 1.280326 1.542836 -0.104752 +v 1.123948 1.517874 0.051626 +v 1.123948 1.542836 0.051626 +v 1.115929 1.517874 0.004846 +v 1.115929 1.542836 0.004846 +v 1.123948 1.517874 -0.041933 +v 1.123948 1.542836 -0.041933 +v -1.321964 1.493954 1.929926 +v -1.321964 1.493954 1.758846 +v -1.150884 1.493954 1.929926 +v -1.150884 1.493954 1.758846 +v -1.321964 1.600048 1.929926 +v -1.321964 1.600048 1.758846 +v -1.150884 1.600048 1.929926 +v -1.346022 1.493954 1.797606 +v -1.354041 1.493954 1.844386 +v -1.346022 1.493954 1.891166 +v -1.321964 1.634035 1.929926 +v -1.321964 1.671146 1.929926 +v -1.321964 1.710339 1.929926 +v -1.321964 1.569880 1.758846 +v -1.321964 1.542836 1.758846 +v -1.321964 1.517874 1.758846 +v -1.189644 1.493954 1.734788 +v -1.236424 1.493954 1.726768 +v -1.283203 1.493954 1.734788 +v -1.150884 1.542836 1.758846 +v -1.150884 1.517874 1.758846 +v -1.126825 1.493954 1.891166 +v -1.118806 1.493954 1.844386 +v -1.126825 1.493954 1.797606 +v -1.150884 1.569880 1.929926 +v -1.150884 1.542836 1.929926 +v -1.150884 1.517874 1.929926 +v -1.283203 1.493954 1.953984 +v -1.236424 1.493954 1.962003 +v -1.189644 1.493954 1.953984 +v -1.321964 1.517874 1.929926 +v -1.321964 1.542836 1.929926 +v -1.321964 1.569880 1.929926 +v -1.321964 1.710339 1.758846 +v -1.321964 1.671146 1.758846 +v -1.321964 1.634035 1.758846 +v -1.150884 1.710339 1.929926 +v -1.150884 1.671146 1.929926 +v -1.150884 1.634035 1.929926 +v -1.189644 1.600048 1.953984 +v -1.236424 1.600048 1.962003 +v -1.283203 1.600048 1.953984 +v -1.126825 1.600048 1.891166 +v -1.283203 1.600048 1.734788 +v -1.346022 1.600048 1.891166 +v -1.354041 1.600048 1.844386 +v -1.346022 1.600048 1.797606 +v -1.346022 1.634035 1.891166 +v -1.346022 1.671146 1.891166 +v -1.346022 1.710339 1.891166 +v -1.354041 1.634035 1.844386 +v -1.354041 1.671146 1.844386 +v -1.354041 1.710339 1.844386 +v -1.346022 1.634035 1.797606 +v -1.346022 1.671146 1.797606 +v -1.346022 1.710339 1.797606 +v -1.283203 1.634035 1.734788 +v -1.283203 1.671146 1.734788 +v -1.283203 1.710339 1.734788 +v -1.126825 1.634035 1.891166 +v -1.126825 1.671146 1.891166 +v -1.126825 1.710339 1.891166 +v -1.189644 1.634035 1.953984 +v -1.189644 1.671146 1.953984 +v -1.189644 1.710339 1.953984 +v -1.236424 1.634035 1.962003 +v -1.236424 1.671146 1.962003 +v -1.236424 1.710339 1.962003 +v -1.283203 1.634035 1.953984 +v -1.283203 1.671146 1.953984 +v -1.283203 1.710339 1.953984 +v -1.291668 1.493954 1.789141 +v -1.236424 1.493954 1.785577 +v -1.181179 1.493954 1.789141 +v -1.295233 1.493954 1.844386 +v -1.236424 1.493954 1.844386 +v -1.177615 1.493954 1.844386 +v -1.291668 1.493954 1.899631 +v -1.236424 1.493954 1.903195 +v -1.181179 1.493954 1.899631 +v -1.189644 1.517874 1.953984 +v -1.189644 1.542836 1.953984 +v -1.189644 1.569880 1.953984 +v -1.236424 1.517874 1.962003 +v -1.236424 1.542836 1.962003 +v -1.236424 1.569880 1.962003 +v -1.283203 1.517874 1.953984 +v -1.283203 1.542836 1.953984 +v -1.283203 1.569880 1.953984 +v -1.126825 1.517874 1.797606 +v -1.126825 1.542836 1.797606 +v -1.118806 1.517874 1.844386 +v -1.118806 1.542836 1.844386 +v -1.126825 1.517874 1.891166 +v -1.126825 1.542836 1.891166 +v -1.126825 1.569880 1.891166 +v -1.283203 1.517874 1.734788 +v -1.283203 1.542836 1.734788 +v -1.283203 1.569880 1.734788 +v -1.236424 1.517874 1.726768 +v -1.236424 1.542836 1.726768 +v -1.189644 1.517874 1.734788 +v -1.189644 1.542836 1.734788 +v -1.346022 1.517874 1.891166 +v -1.346022 1.542836 1.891166 +v -1.346022 1.569880 1.891166 +v -1.354041 1.517874 1.844386 +v -1.354041 1.542836 1.844386 +v -1.354041 1.569880 1.844386 +v -1.346022 1.517874 1.797606 +v -1.346022 1.542836 1.797606 +v -1.346022 1.569880 1.797606 +v 1.148006 1.493954 1.929926 +v 1.148006 1.493954 1.758846 +v 1.319087 1.493954 1.929926 +v 1.319087 1.493954 1.758846 +v 1.148006 1.600048 1.929926 +v 1.319087 1.600048 1.758846 +v 1.319087 1.600048 1.929926 +v 1.123948 1.493954 1.797606 +v 1.115929 1.493954 1.844386 +v 1.123948 1.493954 1.891166 +v 1.148006 1.634035 1.929926 +v 1.148006 1.671146 1.929926 +v 1.148006 1.710339 1.929926 +v 1.148006 1.542836 1.758846 +v 1.148006 1.517874 1.758846 +v 1.280326 1.493954 1.734788 +v 1.233546 1.493954 1.726768 +v 1.186767 1.493954 1.734788 +v 1.319087 1.569880 1.758846 +v 1.319087 1.542836 1.758846 +v 1.319087 1.517874 1.758846 +v 1.343145 1.493954 1.891166 +v 1.351164 1.493954 1.844386 +v 1.343145 1.493954 1.797606 +v 1.319087 1.569880 1.929926 +v 1.319087 1.542836 1.929926 +v 1.319087 1.517874 1.929926 +v 1.186767 1.493954 1.953984 +v 1.233546 1.493954 1.962003 +v 1.280326 1.493954 1.953984 +v 1.148006 1.517874 1.929926 +v 1.148006 1.542836 1.929926 +v 1.148006 1.569880 1.929926 +v 1.319087 1.710339 1.758846 +v 1.319087 1.671146 1.758846 +v 1.319087 1.634035 1.758846 +v 1.319087 1.710339 1.929926 +v 1.319087 1.671146 1.929926 +v 1.319087 1.634035 1.929926 +v 1.280326 1.600048 1.953984 +v 1.233546 1.600048 1.962003 +v 1.186767 1.600048 1.953984 +v 1.343145 1.600048 1.797606 +v 1.351164 1.600048 1.844386 +v 1.343145 1.600048 1.891166 +v 1.123948 1.600048 1.891166 +v 1.123948 1.634035 1.891166 +v 1.123948 1.671146 1.891166 +v 1.123948 1.710339 1.891166 +v 1.343145 1.634035 1.797606 +v 1.343145 1.671146 1.797606 +v 1.343145 1.710339 1.797606 +v 1.351164 1.634035 1.844386 +v 1.351164 1.671146 1.844386 +v 1.351164 1.710339 1.844386 +v 1.343145 1.634035 1.891166 +v 1.343145 1.671146 1.891166 +v 1.343145 1.710339 1.891166 +v 1.280326 1.634035 1.953984 +v 1.280326 1.671146 1.953984 +v 1.280326 1.710339 1.953984 +v 1.233546 1.634035 1.962003 +v 1.233546 1.671146 1.962003 +v 1.233546 1.710339 1.962003 +v 1.186767 1.634035 1.953984 +v 1.186767 1.671146 1.953984 +v 1.186767 1.710339 1.953984 +v 1.178302 1.493954 1.789141 +v 1.233546 1.493954 1.785577 +v 1.288791 1.493954 1.789141 +v 1.174738 1.493954 1.844386 +v 1.233546 1.493954 1.844386 +v 1.292356 1.493954 1.844386 +v 1.178302 1.493954 1.899631 +v 1.233546 1.493954 1.903195 +v 1.288791 1.493954 1.899631 +v 1.280326 1.517874 1.953984 +v 1.280326 1.542836 1.953984 +v 1.280326 1.569880 1.953984 +v 1.233546 1.517874 1.962003 +v 1.233546 1.542836 1.962003 +v 1.233546 1.569880 1.962003 +v 1.186767 1.517874 1.953984 +v 1.186767 1.542836 1.953984 +v 1.186767 1.569880 1.953984 +v 1.343145 1.517874 1.797606 +v 1.343145 1.542836 1.797606 +v 1.343145 1.569880 1.797606 +v 1.351164 1.517874 1.844386 +v 1.351164 1.542836 1.844386 +v 1.351164 1.569880 1.844386 +v 1.343145 1.517874 1.891166 +v 1.343145 1.542836 1.891166 +v 1.343145 1.569880 1.891166 +v 1.186767 1.517874 1.734788 +v 1.186767 1.542836 1.734788 +v 1.233546 1.517874 1.726768 +v 1.233546 1.542836 1.726768 +v 1.280326 1.517874 1.734788 +v 1.280326 1.542836 1.734788 +v 1.123948 1.517874 1.891166 +v 1.123948 1.542836 1.891166 +v 1.123948 1.569880 1.891166 +v 1.115929 1.517874 1.844386 +v 1.115929 1.542836 1.844386 +v 1.123948 1.517874 1.797606 +v 1.123948 1.542836 1.797606 +v 0.000000 0.000000 1.842056 +v 0.000000 1.348322 2.072081 +v 0.000000 1.467010 2.150643 +v 0.000000 1.733418 2.150643 +v -1.497289 1.348322 0.000000 +v -1.554058 1.467010 0.000000 +v -1.554058 1.733418 0.000000 +v 0.000000 0.000000 0.000000 +v 0.000000 0.000000 -1.842056 +v 0.000000 1.348322 -2.072081 +v 1.497289 1.348322 0.000000 +v 0.000000 1.467010 -2.150643 +v 1.554058 1.467010 0.000000 +v 1.554058 1.733418 0.000000 +v 0.000000 1.733418 -2.150643 +v 0.000000 1.733418 -1.888462 +v 0.000000 1.733418 1.888462 +v 1.351164 1.733418 1.844386 +v 1.343145 1.733418 1.797606 +v 1.343145 1.733418 1.891166 +v 1.319087 1.733418 1.929926 +v 1.319087 1.733418 1.758846 +v 1.280326 1.733418 1.953984 +v 1.233546 1.733418 1.962003 +v 1.280397 1.569880 1.734832 +v 1.280397 1.563684 1.734832 +v 1.280326 1.563684 1.734788 +v 1.280397 1.600048 1.734832 +v 1.186767 1.733418 1.953984 +v 1.148006 1.733418 1.929926 +v 1.148006 1.563684 1.758846 +v 1.186767 1.563684 1.734788 +v 1.123485 1.710339 1.888462 +v 1.123485 1.733418 1.888462 +v 1.123948 1.733418 1.891166 +v 1.123485 1.671146 1.888462 +v 1.123485 1.634035 1.888462 +v 1.123485 1.600048 1.888462 +v 1.123485 1.569880 1.888462 +v 1.123948 1.563684 1.797606 +v 1.115929 1.563684 1.844386 +v 1.123485 1.563684 1.888462 +v -1.126362 1.733418 1.888462 +v -1.126825 1.733418 1.891166 +v -1.126362 1.710339 1.888462 +v -1.126362 1.671146 1.888462 +v -1.126362 1.634035 1.888462 +v -1.126362 1.600048 1.888462 +v -1.126362 1.569880 1.888462 +v -1.118806 1.563684 1.844386 +v -1.150884 1.563684 1.758846 +v -1.126825 1.563684 1.797606 +v -1.126362 1.563684 1.888462 +v -1.189644 1.733418 1.953984 +v -1.150884 1.733418 1.929926 +v -1.236424 1.733418 1.962003 +v -1.321964 1.733418 1.758846 +v -1.283203 1.733418 1.953984 +v -1.321964 1.733418 1.929926 +v -1.346022 1.733418 1.797606 +v -1.354041 1.733418 1.844386 +v -1.346022 1.733418 1.891166 +v 1.350333 1.733418 0.000000 +v 1.351164 1.733418 0.004846 +v 1.343145 1.733418 -0.041933 +v 1.343145 1.733418 0.051626 +v 1.319087 1.733418 0.090386 +v 1.280397 1.634035 0.114401 +v 1.280397 1.600048 0.114401 +v 1.280397 1.569880 0.114401 +v 1.280397 1.563684 0.114401 +v 1.280326 1.563684 0.114444 +v 1.280397 1.671146 0.114401 +v 1.280397 1.710339 0.114401 +v 1.280397 1.733418 0.114401 +v 1.233546 1.563684 0.122464 +v 1.233546 1.563684 1.726768 +v 1.280397 1.710339 1.734832 +v 1.280397 1.733418 1.734831 +v 1.280397 1.671146 1.734832 +v 1.280397 1.634035 1.734832 +v 1.186767 1.563684 0.114444 +v 1.148006 1.563684 0.090386 +v 1.123948 1.563684 0.051626 +v 1.115929 1.563684 0.004846 +v 1.123948 1.563684 -0.041933 +v -1.118806 1.563684 0.004846 +v -1.126825 1.563684 -0.041933 +v -1.126825 1.563684 0.051626 +v -1.150884 1.563684 0.090386 +v -1.189644 1.563684 0.114444 +v -1.236424 1.563684 0.122464 +v -1.236424 1.563684 1.726768 +v -1.189644 1.563684 1.734788 +v -1.280397 1.671146 0.114926 +v -1.280397 1.634035 0.114926 +v -1.280397 1.569880 0.114926 +v -1.280397 1.600048 0.114926 +v -1.280397 1.563684 0.114926 +v -1.280397 1.710339 0.114926 +v -1.280397 1.733419 0.114926 +v -1.283203 1.733418 0.114444 +v -1.280397 1.563684 1.734307 +v -1.280397 1.710339 1.734307 +v -1.280397 1.733418 1.734307 +v -1.283203 1.733418 1.734788 +v -1.280397 1.671146 1.734307 +v -1.280397 1.569880 1.734306 +v -1.280397 1.634035 1.734307 +v -1.280397 1.600048 1.734307 +v -1.346022 1.733418 0.051626 +v -1.354041 1.733418 0.004846 +v -1.321964 1.733418 0.090386 +v -1.346022 1.733418 -0.041933 +v -1.353211 1.733418 0.000000 +v 1.319087 1.733418 -1.749153 +v 1.343145 1.733418 -1.787914 +v 1.280397 1.634035 -1.725139 +v 1.280397 1.600048 -1.725139 +v 1.280397 1.671146 -1.725139 +v 1.280397 1.569880 -1.725139 +v 1.280397 1.563684 -1.725139 +v 1.280326 1.563684 -1.725095 +v 1.280397 1.710339 -0.104708 +v 1.280397 1.733418 -0.104708 +v 1.319087 1.733418 -0.080694 +v 1.280397 1.671146 -0.104708 +v 1.280397 1.634035 -0.104708 +v 1.280397 1.600048 -0.104708 +v 1.280397 1.733418 -1.725139 +v 1.280397 1.710339 -1.725139 +v 1.233546 1.563684 -1.717076 +v 1.280326 1.563684 -0.104752 +v 1.233546 1.563684 -0.112771 +v 1.280397 1.569880 -0.104708 +v 1.280397 1.563684 -0.104708 +v 1.186767 1.563684 -1.725095 +v 1.148006 1.563684 -1.749153 +v 1.186767 1.563684 -0.104752 +v 1.148006 1.563684 -0.080694 +v 1.123948 1.563684 -1.787914 +v 1.115929 1.563684 -1.834693 +v -1.118806 1.563684 -1.834693 +v -1.126825 1.563684 -1.787914 +v -1.150884 1.563684 -1.749153 +v -1.150884 1.563684 -0.080694 +v -1.189644 1.563684 -1.725095 +v -1.236424 1.563684 -1.717076 +v -1.236424 1.563684 -0.112771 +v -1.189644 1.563684 -0.104752 +v -1.283203 1.733418 -1.725095 +v -1.280397 1.733418 -1.724614 +v -1.280397 1.710339 -1.724614 +v -1.280397 1.671146 -1.724614 +v -1.280397 1.634035 -1.724614 +v -1.280397 1.600048 -1.724614 +v -1.280397 1.569880 -1.724614 +v -1.280397 1.563684 -1.724614 +v -1.280397 1.600048 -0.105233 +v -1.280397 1.634035 -0.105233 +v -1.283203 1.733418 -0.104752 +v -1.280397 1.733418 -0.105233 +v -1.280397 1.710339 -0.105233 +v -1.280397 1.569880 -0.105233 +v -1.280397 1.563684 -0.105233 +v -1.280397 1.671146 -0.105233 +v -1.321964 1.733418 -0.080694 +v -1.321964 1.733418 -1.749153 +v -1.346022 1.733418 -1.787914 +v 1.351164 1.733418 -1.834693 +v 1.343145 1.733418 -1.881473 +v 1.123948 1.563684 -1.881473 +v -1.354041 1.733418 -1.834693 +v -1.346022 1.733418 -1.881473 +v 1.319087 1.733418 -1.920233 +v 1.128286 1.569880 -1.888462 +v 1.128286 1.563684 -1.888462 +v -1.126825 1.563684 -1.881473 +v 1.148006 1.733418 -1.920233 +v 1.128286 1.733418 -1.888462 +v 1.128286 1.710339 -1.888462 +v 1.128286 1.671146 -1.888462 +v 1.128286 1.634035 -1.888462 +v 1.128286 1.600048 -1.888462 +v -1.131163 1.710339 -1.888462 +v -1.131163 1.671146 -1.888462 +v -1.131163 1.634035 -1.888462 +v -1.131163 1.600048 -1.888462 +v -1.150884 1.733418 -1.920233 +v -1.131163 1.733418 -1.888462 +v -1.131163 1.569880 -1.888462 +v -1.131163 1.563684 -1.888462 +v -1.321964 1.733418 -1.920233 +v 1.280326 1.733418 -1.944292 +v 1.186767 1.733418 -1.944292 +v -1.189644 1.733418 -1.944292 +v -1.283203 1.733418 -1.944292 +v 1.233546 1.733418 -1.952311 +v -1.236424 1.733418 -1.952311 +v 1.239295 0.000000 1.402117 +v 1.239295 0.000000 -1.402117 +v 1.239295 0.000000 0.000000 +v -1.239295 0.000000 1.402117 +v -1.239295 0.000000 0.000000 +v -1.239295 0.000000 -1.402117 +v 1.445211 0.981324 0.975164 +v 1.367395 0.911771 0.932339 +v 1.445211 0.981324 -0.975164 +v 1.367395 0.911771 -0.932339 +v 1.373292 0.911771 0.000000 +v 1.452037 0.981245 0.000000 +v 1.260878 0.000000 1.402117 +v 1.331073 -0.000000 1.480751 +v 1.331073 0.000000 -1.480751 +v 1.260878 -0.000000 -1.402117 +v -1.445211 0.981324 -0.975164 +v -1.367395 0.911771 -0.932339 +v -1.260878 0.000000 -1.402117 +v -1.331073 -0.000000 -1.480751 +v -1.331073 0.000000 1.480751 +v -1.260878 -0.000000 1.402117 +v -1.367395 0.911771 0.932339 +v -1.445211 0.981324 0.975164 +v -1.373292 0.911771 0.000000 +v -1.452037 0.981245 0.000000 +v -0.965189 0.000000 1.842056 +v -1.331073 0.000000 1.480751 +v -1.105207 0.000000 1.814553 +v -1.223908 0.000000 1.736232 +v -1.303222 0.000000 1.619017 +v -1.093508 1.322081 2.031755 +v -1.465674 1.319852 1.641865 +v -1.233708 1.319227 1.997951 +v -1.353667 1.317801 1.911985 +v -1.435122 1.318021 1.786944 +v -1.182193 1.467010 2.150643 +v -1.554058 1.467010 1.767876 +v -1.324500 1.467010 2.121507 +v -1.445142 1.467010 2.038533 +v -1.525752 1.467010 1.914355 +v -1.554058 1.733418 1.768824 +v -1.182721 1.733418 2.150643 +v -1.525792 1.733418 1.914940 +v -1.445296 1.733418 2.038811 +v -1.324826 1.733418 2.121579 +v 1.331073 -0.000000 1.480751 +v 0.965189 0.000000 1.842056 +v 1.303222 -0.000000 1.619017 +v 1.223908 0.000000 1.736232 +v 1.105207 0.000000 1.814553 +v 1.465674 1.319852 1.641865 +v 1.093508 1.322081 2.031755 +v 1.435122 1.318021 1.786944 +v 1.353667 1.317801 1.911985 +v 1.233708 1.319227 1.997951 +v 1.554058 1.467010 1.767876 +v 1.182193 1.467010 2.150643 +v 1.525752 1.467010 1.914355 +v 1.445142 1.467010 2.038533 +v 1.324500 1.467010 2.121507 +v 1.182721 1.733418 2.150643 +v 1.554058 1.733418 1.768824 +v 1.324826 1.733418 2.121579 +v 1.445296 1.733418 2.038811 +v 1.525792 1.733418 1.914940 +v -1.331073 -0.000000 -1.480751 +v -0.965189 0.000000 -1.842056 +v -1.303222 -0.000000 -1.619016 +v -1.223908 0.000000 -1.736232 +v -1.105207 0.000000 -1.814553 +v -1.465674 1.319852 -1.641865 +v -1.093508 1.322081 -2.031755 +v -1.435122 1.318021 -1.786944 +v -1.353667 1.317801 -1.911985 +v -1.233708 1.319227 -1.997951 +v -1.554058 1.467010 -1.767876 +v -1.182193 1.467010 -2.150643 +v -1.525752 1.467010 -1.914355 +v -1.445142 1.467010 -2.038533 +v -1.324500 1.467010 -2.121507 +v -1.182721 1.733418 -2.150643 +v -1.554058 1.733418 -1.768824 +v -1.324826 1.733418 -2.121579 +v -1.445296 1.733418 -2.038811 +v -1.525792 1.733418 -1.914940 +v 0.965189 0.000000 -1.842056 +v 1.331073 0.000000 -1.480751 +v 1.105207 0.000000 -1.814553 +v 1.223908 0.000000 -1.736232 +v 1.303222 0.000000 -1.619016 +v 1.093508 1.322081 -2.031755 +v 1.465674 1.319852 -1.641865 +v 1.233708 1.319227 -1.997951 +v 1.353667 1.317801 -1.911985 +v 1.435122 1.318021 -1.786944 +v 1.182193 1.467010 -2.150643 +v 1.554058 1.467010 -1.767876 +v 1.324500 1.467010 -2.121507 +v 1.445142 1.467010 -2.038533 +v 1.525752 1.467010 -1.914355 +v 1.554058 1.733418 -1.768824 +v 1.182721 1.733418 -2.150643 +v 1.525792 1.733418 -1.914940 +v 1.445296 1.733418 -2.038811 +v 1.324826 1.733418 -2.121579 +v 1.186751 0.459175 0.000000 +v 1.186751 0.746341 0.000000 +v 1.271073 0.459175 0.000000 +v 1.271073 0.746341 0.000000 +v -1.186751 0.459175 0.000000 +v -1.186751 0.746341 0.000000 +v -1.271073 0.459175 0.000000 +v -1.271073 0.746341 0.000000 +v 1.186751 0.459175 0.474073 +v 1.186751 0.538839 0.553737 +v 1.186751 0.479729 0.533184 +v 1.186751 0.666677 0.553737 +v 1.186751 0.746341 0.474073 +v 1.186751 0.725788 0.533184 +v 1.186751 0.538839 -0.553737 +v 1.186751 0.459175 -0.474073 +v 1.186751 0.479729 -0.533184 +v 1.186751 0.746341 -0.474073 +v 1.186751 0.666677 -0.553737 +v 1.186751 0.725788 -0.533184 +v 1.271073 0.538839 0.553737 +v 1.271073 0.459175 0.474073 +v 1.271073 0.479729 0.533184 +v 1.271073 0.746341 0.474073 +v 1.271073 0.666677 0.553737 +v 1.271073 0.725788 0.533184 +v 1.271073 0.459175 -0.474073 +v 1.271073 0.538839 -0.553737 +v 1.271073 0.479729 -0.533184 +v 1.271073 0.666677 -0.553737 +v 1.271073 0.746341 -0.474073 +v 1.271073 0.725788 -0.533184 +v -1.186751 0.538839 0.553737 +v -1.186751 0.459175 0.474073 +v -1.186751 0.479729 0.533184 +v -1.186751 0.746341 0.474073 +v -1.186751 0.666677 0.553737 +v -1.186751 0.725788 0.533184 +v -1.186751 0.459175 -0.474073 +v -1.186751 0.538839 -0.553737 +v -1.186751 0.479729 -0.533184 +v -1.186751 0.666677 -0.553737 +v -1.186751 0.746341 -0.474073 +v -1.186751 0.725788 -0.533184 +v -1.271073 0.459175 0.474073 +v -1.271073 0.538839 0.553737 +v -1.271073 0.479729 0.533184 +v -1.271073 0.666677 0.553737 +v -1.271073 0.746341 0.474073 +v -1.271073 0.725788 0.533184 +v -1.271073 0.538839 -0.553737 +v -1.271073 0.459175 -0.474073 +v -1.271073 0.479729 -0.533184 +v -1.271073 0.746341 -0.474073 +v -1.271073 0.666677 -0.553737 +v -1.271073 0.725788 -0.533184 +vt 0.625000 0.500000 +vt 0.406599 0.493040 +vt 0.625000 0.458689 +vt 0.625000 0.750000 +vt 0.406599 0.756960 +vt 0.625000 0.791311 +vt 0.625000 0.500000 +vt 0.406599 0.493040 +vt 0.406599 0.500000 +vt 0.406599 0.625000 +vt 0.625000 0.750000 +vt 0.406599 0.750000 +vt 0.406599 0.625000 +vt 0.668213 0.625000 +vt 0.666311 0.750000 +vt 0.666311 0.750000 +vt 0.668213 0.625000 +vt 0.406599 0.756960 +vt 0.406599 0.500000 +vt 0.406599 0.750000 +vt 0.625000 0.458689 +vt 0.666311 0.500000 +vt 0.666311 0.500000 +vt 0.625000 0.791311 +vt 1.000000 0.000000 +vt 1.000000 0.813490 +vt 1.000000 0.000000 +vt 0.511467 0.125000 +vt 0.547621 0.062500 +vt 0.511467 0.062500 +vt 0.547621 0.125000 +vt 0.585803 0.062500 +vt 0.511467 0.187500 +vt 0.547621 0.187500 +vt 0.585803 0.125000 +vt 0.478357 0.062500 +vt 0.511467 0.000000 +vt 0.478357 0.000000 +vt 0.547621 0.000000 +vt 0.585803 0.000000 +vt 0.608287 0.000000 +vt 0.608287 0.062500 +vt 0.585803 0.187500 +vt 0.608287 0.125000 +vt 0.585803 0.250000 +vt 0.608287 0.187500 +vt 0.547621 0.250000 +vt 0.511467 0.250000 +vt 0.478357 0.250000 +vt 0.478357 0.187500 +vt 0.478357 0.125000 +vt 0.511467 0.375000 +vt 0.547621 0.312500 +vt 0.511467 0.312500 +vt 0.547621 0.375000 +vt 0.585803 0.312500 +vt 0.511467 0.437500 +vt 0.547621 0.437500 +vt 0.585803 0.375000 +vt 0.478357 0.312500 +vt 0.608287 0.250000 +vt 0.608287 0.312500 +vt 0.585803 0.437500 +vt 0.608287 0.375000 +vt 0.585803 0.500000 +vt 0.608287 0.437500 +vt 0.547621 0.500000 +vt 0.511467 0.500000 +vt 0.478357 0.500000 +vt 0.478357 0.437500 +vt 0.478357 0.375000 +vt 0.478357 0.551231 +vt 0.511467 0.551231 +vt 0.585803 0.551231 +vt 0.608287 0.500000 +vt 0.585803 1.000000 +vt 0.608287 0.937500 +vt 0.585803 0.937500 +vt 0.547621 1.000000 +vt 0.547621 0.937500 +vt 0.511467 1.000000 +vt 0.511467 0.937500 +vt 0.478357 1.000000 +vt 0.478357 0.937500 +vt 0.511467 0.375000 +vt 0.547621 0.312500 +vt 0.511467 0.312500 +vt 0.547621 0.375000 +vt 0.585803 0.312500 +vt 0.511467 0.437500 +vt 0.547621 0.437500 +vt 0.585803 0.375000 +vt 0.478357 0.312500 +vt 0.511467 0.250000 +vt 0.478357 0.250000 +vt 0.547621 0.250000 +vt 0.585803 0.250000 +vt 0.608287 0.312500 +vt 0.608287 0.250000 +vt 0.585803 0.437500 +vt 0.608287 0.375000 +vt 0.585803 0.500000 +vt 0.608287 0.437500 +vt 0.547621 0.500000 +vt 0.511467 0.500000 +vt 0.478357 0.500000 +vt 0.478357 0.437500 +vt 0.478357 0.375000 +vt 0.511467 0.625000 +vt 0.547621 0.562500 +vt 0.511467 0.562500 +vt 0.547621 0.625000 +vt 0.585803 0.562500 +vt 0.511467 0.687500 +vt 0.547621 0.687500 +vt 0.585803 0.625000 +vt 0.478357 0.562500 +vt 0.608287 0.500000 +vt 0.608287 0.562500 +vt 0.585803 0.687500 +vt 0.608287 0.625000 +vt 0.585803 0.750000 +vt 0.608287 0.687500 +vt 0.547621 0.750000 +vt 0.511467 0.750000 +vt 0.478357 0.750000 +vt 0.478357 0.687500 +vt 0.478357 0.625000 +vt 0.478357 0.812386 +vt 0.511467 0.812386 +vt 0.547621 0.812387 +vt 0.585803 0.812387 +vt 0.608287 0.750000 +vt 0.511467 0.125000 +vt 0.547621 0.062500 +vt 0.511467 0.062500 +vt 0.547621 0.125000 +vt 0.585803 0.062500 +vt 0.511467 0.187500 +vt 0.547621 0.187500 +vt 0.585803 0.125000 +vt 0.478357 0.062500 +vt 0.511467 0.000000 +vt 0.478357 0.000000 +vt 0.547621 0.000000 +vt 0.585803 0.000000 +vt 0.608287 0.000000 +vt 0.608287 0.062500 +vt 0.585803 0.187500 +vt 0.608287 0.187500 +vt 0.608287 0.131475 +vt 0.585803 0.250000 +vt 0.547621 0.250000 +vt 0.511467 0.250000 +vt 0.478357 0.250000 +vt 0.478357 0.187500 +vt 0.478357 0.125000 +vt 0.511467 0.312500 +vt 0.547621 0.316250 +vt 0.547621 0.312500 +vt 0.585803 0.312500 +vt 0.478357 0.312500 +vt 0.608287 0.250000 +vt 0.585803 0.316250 +vt 0.608287 0.312500 +vt 0.511467 0.316250 +vt 0.585803 1.000000 +vt 0.608287 0.937500 +vt 0.585803 0.937500 +vt 0.547621 1.000000 +vt 0.547621 0.937500 +vt 0.511467 1.000000 +vt 0.511467 0.937500 +vt 0.478357 1.000000 +vt 0.478357 0.937500 +vt 0.511467 0.625000 +vt 0.547621 0.562500 +vt 0.511467 0.562500 +vt 0.547621 0.625000 +vt 0.585803 0.562500 +vt 0.511467 0.687500 +vt 0.547621 0.687500 +vt 0.585803 0.625000 +vt 0.478357 0.562500 +vt 0.511467 0.500000 +vt 0.478357 0.500000 +vt 0.547621 0.500000 +vt 0.585803 0.500000 +vt 0.608287 0.500000 +vt 0.608287 0.625000 +vt 0.608287 0.618525 +vt 0.585803 0.687500 +vt 0.585803 0.750000 +vt 0.608287 0.687500 +vt 0.547621 0.750000 +vt 0.511467 0.750000 +vt 0.478357 0.750000 +vt 0.478357 0.687500 +vt 0.478357 0.625000 +vt 0.478357 0.812386 +vt 0.511467 0.812386 +vt 0.547621 0.812386 +vt 0.585803 0.812386 +vt 0.608287 0.750000 +vt 0.511467 0.125000 +vt 0.547621 0.062500 +vt 0.511467 0.062500 +vt 0.547621 0.125000 +vt 0.585803 0.062500 +vt 0.511467 0.187500 +vt 0.547621 0.187500 +vt 0.585803 0.125000 +vt 0.478357 0.062500 +vt 0.511467 0.000000 +vt 0.478357 0.000000 +vt 0.547621 0.000000 +vt 0.585803 0.000000 +vt 0.608287 0.000000 +vt 0.608287 0.062500 +vt 0.585803 0.187500 +vt 0.608287 0.125000 +vt 0.585803 0.250000 +vt 0.608287 0.187500 +vt 0.547621 0.250000 +vt 0.511467 0.250000 +vt 0.478357 0.250000 +vt 0.478357 0.187500 +vt 0.478357 0.125000 +vt 0.511467 0.316250 +vt 0.547621 0.312500 +vt 0.511467 0.312500 +vt 0.547621 0.316250 +vt 0.585803 0.312500 +vt 0.478357 0.312500 +vt 0.608287 0.250000 +vt 0.585803 0.316250 +vt 0.608287 0.312500 +vt 0.478357 0.316250 +vt 0.585803 0.750000 +vt 0.608287 0.687500 +vt 0.585803 0.687500 +vt 0.547621 0.750000 +vt 0.547621 0.687500 +vt 0.511467 0.750000 +vt 0.511467 0.687500 +vt 0.478357 0.750000 +vt 0.478357 0.687500 +vt 0.511467 0.875000 +vt 0.547621 0.812500 +vt 0.511467 0.812500 +vt 0.547621 0.875000 +vt 0.585803 0.812500 +vt 0.511467 0.937500 +vt 0.547621 0.937500 +vt 0.585803 0.875000 +vt 0.478357 0.812500 +vt 0.608287 0.812500 +vt 0.608287 0.750000 +vt 0.608287 0.875000 +vt 0.608287 0.937500 +vt 0.585803 0.937500 +vt 0.608287 1.000000 +vt 0.547621 1.000000 +vt 0.511467 1.000000 +vt 0.478357 1.000000 +vt 0.478357 0.937500 +vt 0.478357 0.875000 +vt 0.511467 0.062500 +vt 0.547621 0.066112 +vt 0.547621 0.062500 +vt 0.585803 0.066112 +vt 0.585803 0.062500 +vt 0.478357 0.062500 +vt 0.511467 0.000000 +vt 0.478357 0.000000 +vt 0.547621 0.000000 +vt 0.585803 0.000000 +vt 0.608287 0.000000 +vt 0.608287 0.066112 +vt 0.608287 0.062500 +vt 0.478357 0.066112 +vt 0.511467 0.625000 +vt 0.547621 0.562500 +vt 0.511467 0.562500 +vt 0.547621 0.625000 +vt 0.585803 0.562500 +vt 0.511467 0.687500 +vt 0.547621 0.687500 +vt 0.585803 0.625000 +vt 0.478357 0.562500 +vt 0.511467 0.500000 +vt 0.478357 0.500000 +vt 0.547621 0.500000 +vt 0.585803 0.500000 +vt 0.608287 0.500000 +vt 0.608287 0.562500 +vt 0.585803 0.687500 +vt 0.608287 0.625000 +vt 0.585803 0.750000 +vt 0.608287 0.687500 +vt 0.547621 0.750000 +vt 0.511467 0.750000 +vt 0.478357 0.750000 +vt 0.478357 0.687500 +vt 0.478357 0.625000 +vt 0.511467 0.875000 +vt 0.547621 0.812500 +vt 0.511467 0.812500 +vt 0.547621 0.875000 +vt 0.585803 0.812500 +vt 0.511467 0.937500 +vt 0.547621 0.937500 +vt 0.585803 0.875000 +vt 0.478357 0.812500 +vt 0.608287 0.750000 +vt 0.608287 0.812500 +vt 0.585803 0.937500 +vt 0.608287 0.875000 +vt 0.585803 1.000000 +vt 0.608287 0.937500 +vt 0.547621 1.000000 +vt 0.511467 1.000000 +vt 0.478357 1.000000 +vt 0.478357 0.937500 +vt 0.478357 0.875000 +vt 1.000000 0.897371 +vt 1.000000 0.879349 +vt 1.000000 0.982669 +vt 1.000000 0.822022 +vt 1.000000 0.000000 +vt 0.749786 1.000000 +vt 0.000000 1.000000 +vt 0.760713 1.000000 +vt 0.000000 1.000000 +vt 0.761053 1.000000 +vt 1.000000 0.813490 +vt 1.000000 0.000000 +vt 1.000000 0.000000 +vt 1.000000 0.982666 +vt 1.000000 0.879349 +vt 1.000000 0.897371 +vt 1.000000 0.000000 +vt 1.000000 0.822022 +vt 0.749786 1.000000 +vt 0.000000 1.000000 +vt 0.760713 1.000000 +vt 1.000000 0.813490 +vt 1.000000 0.890403 +vt 1.000000 0.853090 +vt 1.000000 0.874842 +vt 1.000000 0.822022 +vt 0.749786 1.000000 +vt 0.000000 1.000000 +vt 0.000000 1.000000 +vt 0.760713 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.982667 +vt 1.000000 0.892866 +vt 1.000000 0.874842 +vt 1.000000 0.822022 +vt 0.749786 1.000000 +vt 0.760713 1.000000 +vt 0.761053 1.000000 +vt 0.585803 0.437614 +vt 0.547621 0.437614 +vt 0.511467 0.198769 +vt 0.478357 0.198769 +vt 0.585803 0.198769 +vt 0.608287 0.198770 +vt 0.547621 0.933750 +vt 0.511467 0.933750 +vt 0.585803 0.933750 +vt 0.585803 0.437614 +vt 0.608287 0.437614 +vt 0.511467 0.437614 +vt 0.608287 0.933750 +vt 0.547621 0.933750 +vt 0.511467 0.933750 +vt 0.478357 0.437614 +vt 0.547621 0.437614 +vt 0.547621 0.198769 +vt 0.585803 0.683888 +vt 0.547621 0.683888 +vt 0.511467 0.683888 +vt 0.585803 0.933750 +vt 0.608287 0.933750 +vt 0.608287 0.437614 +vt 0.511467 0.437614 +vt 0.478357 0.933750 +vt 0.478357 0.933750 +vt 0.478357 0.437614 +vt 0.478357 0.683888 +vt 0.608287 0.683888 +vt 1.000000 0.813490 +vt 1.000000 0.887563 +vt 1.000000 0.892387 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +vt 0.854818 1.000000 +vt 0.848504 1.000000 +vt 1.000000 0.822463 +vt 1.000000 0.890404 +vt 0.901663 0.995497 +vt 0.848504 1.000000 +vt 0.854818 1.000000 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.892387 +vt 1.000000 0.887563 +vt 0.761053 1.000000 +vt 0.901663 0.995495 +vt 1.000000 0.890403 +vt 1.000000 0.822463 +vt 0.848504 1.000000 +vt 0.854818 1.000000 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.892387 +vt 1.000000 0.887563 +vt 0.761053 1.000000 +vt 0.901663 0.995495 +vt 1.000000 0.982667 +vt 1.000000 0.822463 +vt 1.000000 0.887563 +vt 1.000000 0.892387 +vt 1.000000 1.000000 +vt 1.000000 1.000000 +vt 0.854818 1.000000 +vt 0.848504 1.000000 +vt 1.000000 0.822463 +vt 1.000000 0.890403 +vt 0.901663 0.995496 +vt 0.547621 0.551231 +vt 0.608287 0.551230 +vt 0.608287 1.000000 +vt 0.608287 0.812387 +vt 0.608287 0.125000 +vt 0.608287 0.316249 +vt 0.478357 0.316250 +vt 0.608287 1.000000 +vt 0.608287 0.562500 +vt 0.608287 0.812386 +vt 0.608287 0.316250 +vt 0.585803 1.000000 +vt 0.511467 0.066112 +vt 0.608287 1.000000 +vt 1.000000 0.053214 +vt 1.000000 0.857596 +vt 1.000000 0.908559 +vt 1.000000 1.000000 +vt 1.000000 0.912287 +vt 1.000000 1.000000 +vt 1.000000 0.879349 +vt 1.000000 0.908558 +vt 1.000000 0.897371 +vt 1.000000 0.878092 +vt 1.000000 0.878092 +vt 1.000000 0.835846 +vt 1.000000 0.002253 +vt 1.000000 0.000000 +vt 1.000000 0.024005 +vt 1.000000 0.042028 +vt 1.000000 0.806413 +vt 1.000000 0.053438 +vt 1.000000 0.806637 +vt 1.000000 0.817823 +vt 1.000000 0.000000 +vt 1.000000 0.002253 +vt 1.000000 0.024005 +vt 1.000000 0.857598 +vt 1.000000 0.053194 +vt 1.000000 0.835845 +vt 1.000000 0.908553 +vt 1.000000 1.000000 +vt 1.000000 0.879349 +vt 1.000000 0.912287 +vt 1.000000 0.908558 +vt 1.000000 0.878092 +vt 1.000000 0.042028 +vt 1.000000 0.806657 +vt 1.000000 0.817823 +vt 1.000000 0.897372 +vt 1.000000 0.048707 +vt 1.000000 0.019498 +vt 1.000000 0.037520 +vt 1.000000 0.831340 +vt 1.000000 1.000000 +vt 1.000000 0.907781 +vt 1.000000 0.904052 +vt 1.000000 0.904052 +vt 1.000000 0.878092 +vt 1.000000 1.000000 +vt 1.000000 0.878092 +vt 1.000000 0.892865 +vt 1.000000 0.802129 +vt 1.000000 0.813315 +vt 1.000000 0.048931 +vt 1.000000 0.801906 +vt 1.000000 0.892862 +vt 1.000000 0.019498 +vt 1.000000 0.048687 +vt 1.000000 0.037521 +vt 1.000000 0.853090 +vt 1.000000 0.831339 +vt 1.000000 0.904055 +vt 1.000000 1.000000 +vt 1.000000 0.907780 +vt 1.000000 0.904051 +vt 1.000000 0.878092 +vt 1.000000 0.892865 +vt 1.000000 0.802150 +vt 1.000000 0.813316 +vt 0.365859 0.739828 +vt 0.370426 0.739297 +vt 0.370426 0.633106 +vt 0.376828 0.485150 +vt 0.385731 0.485150 +vt 0.425090 0.375000 +vt 0.376828 0.984962 +vt 0.385731 0.984962 +vt 0.425090 0.875000 +vt 0.395761 0.010204 +vt 0.385731 0.117393 +vt 0.395761 0.117393 +vt 0.376828 0.131966 +vt 0.375000 0.239155 +vt 0.376828 0.239155 +vt 0.376828 0.510811 +vt 0.375000 0.510811 +vt 0.375000 0.618069 +vt 0.375000 0.632572 +vt 0.375000 0.739831 +vt 0.376828 0.739831 +vt 0.360150 0.500000 +vt 0.139569 0.500000 +vt 0.139993 0.500463 +vt 0.359727 0.500463 +vt 0.140776 0.503559 +vt 0.358944 0.503559 +vt 0.139993 0.506655 +vt 0.359727 0.506655 +vt 0.137644 0.509221 +vt 0.362075 0.509221 +vt 0.133860 0.510813 +vt 0.137644 0.619659 +vt 0.129293 0.511344 +vt 0.125000 0.510845 +vt 0.125000 0.618034 +vt 0.133860 0.618066 +vt 0.365859 0.510814 +vt 0.362075 0.619659 +vt 0.129293 0.617536 +vt 0.370426 0.511345 +vt 0.365859 0.618066 +vt 0.374993 0.510813 +vt 0.374993 0.618066 +vt 0.139993 0.622224 +vt 0.370426 0.617536 +vt 0.140776 0.625321 +vt 0.359727 0.622224 +vt 0.139993 0.628417 +vt 0.358944 0.625321 +vt 0.137644 0.630983 +vt 0.359727 0.628417 +vt 0.133860 0.632575 +vt 0.137644 0.741421 +vt 0.362075 0.630983 +vt 0.129293 0.633106 +vt 0.125000 0.632607 +vt 0.125000 0.739796 +vt 0.133860 0.739828 +vt 0.129293 0.739297 +vt 0.365859 0.632575 +vt 0.362075 0.741421 +vt 0.359727 0.743986 +vt 0.139992 0.743986 +vt 0.140776 0.747083 +vt 0.140038 0.750000 +vt 0.358943 0.747082 +vt 0.359681 0.750000 +vt 0.374993 0.739828 +vt 0.374993 0.632575 +vt 0.425090 0.264569 +vt 0.418279 0.264569 +vt 0.406713 0.264569 +vt 0.395761 0.264569 +vt 0.385731 0.264569 +vt 0.418280 0.485150 +vt 0.425090 0.485150 +vt 0.395761 0.485150 +vt 0.406713 0.485150 +vt 0.376828 0.264569 +vt 0.375000 0.264569 +vt 0.375000 0.485150 +vt 0.425090 0.765319 +vt 0.418279 0.765319 +vt 0.406713 0.765318 +vt 0.395761 0.765318 +vt 0.385731 0.765319 +vt 0.418279 0.984962 +vt 0.425090 0.984962 +vt 0.395761 0.984962 +vt 0.406713 0.984962 +vt 0.376828 0.765319 +vt 0.375000 0.765319 +vt 0.375000 0.984962 +vt 0.425090 0.117393 +vt 0.425090 0.010204 +vt 0.418280 0.010204 +vt 0.406713 0.010204 +vt 0.385731 0.010204 +vt 0.376828 0.117393 +vt 0.376828 0.010204 +vt 0.375000 0.117393 +vt 0.418279 0.117393 +vt 0.406713 0.117393 +vt 0.375000 0.010204 +vt 0.425090 0.239155 +vt 0.425090 0.131966 +vt 0.418279 0.131966 +vt 0.406713 0.131966 +vt 0.395761 0.131966 +vt 0.406713 0.239155 +vt 0.385731 0.131966 +vt 0.395761 0.239154 +vt 0.418279 0.239155 +vt 0.375000 0.131966 +vt 0.385731 0.239154 +vt 0.425090 0.618069 +vt 0.425090 0.510811 +vt 0.418280 0.510810 +vt 0.406713 0.510811 +vt 0.406713 0.618069 +vt 0.395761 0.510810 +vt 0.418279 0.618069 +vt 0.385731 0.618069 +vt 0.395761 0.618069 +vt 0.385731 0.510811 +vt 0.376828 0.618069 +vt 0.425090 0.739831 +vt 0.425090 0.632572 +vt 0.418279 0.632572 +vt 0.406713 0.632572 +vt 0.395761 0.632572 +vt 0.406713 0.739831 +vt 0.385731 0.632572 +vt 0.395761 0.739831 +vt 0.418279 0.739831 +vt 0.385731 0.739831 +vt 0.376828 0.632572 +vt 0.690845 0.625000 +vt 0.688946 0.750000 +vt 0.406599 0.470403 +vt 0.625000 0.436054 +vt 0.690845 0.625000 +vt 0.688946 0.500000 +vt 0.406599 0.779597 +vt 0.625000 0.813946 +vt 1.000000 0.495995 +vt 1.000000 0.803858 +vt 0.931050 0.761170 +vt 0.947264 0.761170 +vt 1.000000 0.803858 +vt 1.000000 0.495995 +vt 0.725121 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.495995 +vt 0.725121 1.000000 +vt 1.000000 0.495995 +vt 1.000000 0.803858 +vt 1.000000 0.803858 +vt 0.947264 0.761170 +vt 0.931050 0.761170 +vt 0.725121 1.000000 +vt 0.725121 1.000000 +vt 0.000000 1.000000 +vt 0.931050 0.761170 +vt 0.947264 0.761170 +vt 1.000000 0.803858 +vt 1.000000 0.000000 +vt 1.000000 0.475537 +vt 1.000000 0.803858 +vt 1.000000 0.477545 +vt 1.000000 0.803858 +vt 1.000000 0.477545 +vt 1.000000 0.000000 +vt 1.000000 0.475537 +vt 0.830670 0.995023 +vt 0.973163 0.980850 +vt 0.993025 0.879166 +vt 1.000000 0.803858 +vt 0.993025 0.879166 +vt 0.973163 0.980850 +vt 0.830670 0.995023 +vt 0.993025 0.879165 +vt 0.973163 0.980850 +vt 0.830670 0.995023 +vt 0.830670 0.995023 +vt 0.973163 0.980850 +vt 0.993025 0.879166 +vt 0.947264 0.761170 +vt 0.931050 0.761170 +vt 0.000000 0.000000 +vt 0.931049 0.000000 +vt 0.931050 0.000000 +vt 1.000000 0.000226 +vt 1.000000 0.761170 +vt 1.000000 0.761169 +vt 1.000000 0.000226 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.442932 0.812500 +vt 0.422621 0.937500 +vt 0.448967 0.937500 +vt 0.448967 0.933750 +vt 0.442932 0.933750 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.442932 0.750000 +vt 0.448967 1.000000 +vt 0.422621 1.000000 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.442932 0.562500 +vt 0.422621 0.687500 +vt 0.442932 0.625000 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.442932 0.551231 +vt 0.448967 0.551231 +vt 0.448967 0.500000 +vt 0.442932 0.687500 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.422621 0.375000 +vt 0.448967 0.312500 +vt 0.422621 0.437500 +vt 0.448967 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.448967 0.250000 +vt 0.448967 0.437500 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.422621 0.125000 +vt 0.448967 0.062500 +vt 0.422621 0.187500 +vt 0.448967 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.448967 0.000000 +vt 0.448967 0.187500 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.442932 0.812500 +vt 0.422621 0.937500 +vt 0.442932 0.875000 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.442932 0.812386 +vt 0.448967 0.812386 +vt 0.448967 0.750000 +vt 0.422621 1.000000 +vt 0.442932 0.937500 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.448967 0.562500 +vt 0.422621 0.687500 +vt 0.448967 0.625000 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.448967 0.500000 +vt 0.448967 0.687500 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.422621 0.375000 +vt 0.448967 0.312500 +vt 0.422621 0.437500 +vt 0.448967 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.448967 0.250000 +vt 0.448967 0.437500 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.422621 0.125000 +vt 0.442932 0.062500 +vt 0.422621 0.187500 +vt 0.442932 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.442932 0.000000 +vt 0.448967 0.198769 +vt 0.442932 0.198770 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.442932 0.812500 +vt 0.422621 0.937500 +vt 0.448967 0.937500 +vt 0.448967 0.933750 +vt 0.442932 0.933750 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.442932 0.750000 +vt 0.448967 1.000000 +vt 0.422621 1.000000 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.442932 0.562500 +vt 0.422621 0.687500 +vt 0.442932 0.625000 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.442932 0.500000 +vt 0.442932 0.687500 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.442932 0.316250 +vt 0.448967 0.312500 +vt 0.422621 0.437500 +vt 0.422621 0.375000 +vt 0.442932 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.448967 0.250000 +vt 0.448967 0.316250 +vt 0.442932 0.437500 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.422621 0.125000 +vt 0.448967 0.062500 +vt 0.422621 0.187500 +vt 0.448967 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.448967 0.000000 +vt 0.448967 0.187500 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.442932 0.812500 +vt 0.422621 0.937500 +vt 0.442932 0.875000 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.442932 0.812386 +vt 0.448967 0.812386 +vt 0.448967 0.750000 +vt 0.422621 1.000000 +vt 0.442932 0.937500 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.448967 0.562500 +vt 0.422621 0.687500 +vt 0.448967 0.625000 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.448967 0.500000 +vt 0.448967 0.687500 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.422621 0.375000 +vt 0.442932 0.312500 +vt 0.422621 0.437500 +vt 0.442932 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.442932 0.250000 +vt 0.448967 0.437614 +vt 0.442932 0.437614 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.422621 0.125000 +vt 0.442932 0.062500 +vt 0.422621 0.187500 +vt 0.442932 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.442932 0.000000 +vt 0.442932 0.187500 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.448967 0.812500 +vt 0.422621 0.937500 +vt 0.448967 0.875000 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.448967 0.750000 +vt 0.448967 0.937500 +vt 0.448967 1.000000 +vt 0.422621 1.000000 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.442932 0.562500 +vt 0.422621 0.687500 +vt 0.448967 0.687500 +vt 0.448967 0.683888 +vt 0.442932 0.683888 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.442932 0.500000 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.442932 0.316250 +vt 0.448967 0.312500 +vt 0.422621 0.437500 +vt 0.422621 0.375000 +vt 0.442932 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.448967 0.250000 +vt 0.448967 0.316250 +vt 0.442932 0.437500 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.422621 0.125000 +vt 0.448967 0.062500 +vt 0.422621 0.187500 +vt 0.448967 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.448967 0.000000 +vt 0.448967 0.187500 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.187500 0.562500 +vt 0.250000 0.625000 +vt 0.250000 0.562500 +vt 0.312500 0.562500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.312500 0.687500 +vt 0.312500 0.625000 +vt 0.125000 0.500000 +vt 0.187500 0.500000 +vt 0.250000 0.500000 +vt 0.312500 0.500000 +vt 0.375000 0.500000 +vt 0.375000 0.562500 +vt 0.375000 0.687500 +vt 0.375000 0.625000 +vt 0.375000 0.750000 +vt 0.250000 0.687500 +vt 0.312500 0.750000 +vt 0.187500 0.750000 +vt 0.125000 0.750000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.562500 +vt 0.398303 0.875000 +vt 0.422621 0.812500 +vt 0.398303 0.812500 +vt 0.422621 0.875000 +vt 0.448967 0.812500 +vt 0.422621 0.937500 +vt 0.448967 0.875000 +vt 0.398303 0.750000 +vt 0.422621 0.750000 +vt 0.448967 0.750000 +vt 0.448967 0.937500 +vt 0.448967 1.000000 +vt 0.422621 1.000000 +vt 0.398303 1.000000 +vt 0.398303 0.937500 +vt 0.375000 1.000000 +vt 0.375000 0.937500 +vt 0.375000 0.875000 +vt 0.375000 0.812500 +vt 0.398303 0.625000 +vt 0.422621 0.562500 +vt 0.398303 0.562500 +vt 0.422621 0.625000 +vt 0.448967 0.562500 +vt 0.422621 0.687500 +vt 0.448967 0.625000 +vt 0.398303 0.500000 +vt 0.422621 0.500000 +vt 0.448967 0.500000 +vt 0.448967 0.687500 +vt 0.398303 0.687500 +vt 0.398303 0.375000 +vt 0.422621 0.312500 +vt 0.398303 0.312500 +vt 0.422621 0.375000 +vt 0.442932 0.312500 +vt 0.422621 0.437500 +vt 0.442932 0.375000 +vt 0.375000 0.250000 +vt 0.398303 0.250000 +vt 0.422621 0.250000 +vt 0.442932 0.250000 +vt 0.448967 0.437614 +vt 0.442932 0.437614 +vt 0.398303 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.398303 0.125000 +vt 0.422621 0.062500 +vt 0.398303 0.062500 +vt 0.442932 0.066112 +vt 0.448967 0.062500 +vt 0.422621 0.187500 +vt 0.422621 0.125000 +vt 0.442932 0.125000 +vt 0.375000 0.000000 +vt 0.398303 0.000000 +vt 0.422621 0.000000 +vt 0.448967 0.000000 +vt 0.448967 0.066112 +vt 0.442932 0.187500 +vt 0.398303 0.187500 +vt 0.375000 0.187500 +vt 0.375000 0.125000 +vt 0.375000 0.062500 +vt 0.250000 0.750000 +vt 0.442932 0.875000 +vt 0.250000 0.750000 +vt 0.442932 1.000000 +vt 0.442932 0.187500 +vt 0.250000 0.750000 +vt 0.442932 0.875000 +vt 0.250000 0.750000 +vt 0.442932 1.000000 +vt 0.442932 0.437500 +vt 0.250000 0.750000 +vt 0.442932 0.625000 +vt 0.250000 0.750000 +vt 0.442932 0.437500 +vt 0.875000 0.517983 +vt 0.625000 0.625000 +vt 0.625000 0.517983 +vt 0.375000 0.517983 +vt 0.125000 0.625000 +vt 0.125000 0.517983 +vt 0.555646 0.500000 +vt 0.375000 0.625000 +vt 0.125000 0.732017 +vt 0.875000 0.625000 +vt 0.625000 0.732017 +vt 0.555646 0.250000 +vt 0.444354 0.500000 +vt 0.444354 0.250000 +vt 0.444354 0.750000 +vt 0.392893 0.745360 +vt 0.375000 0.732017 +vt 0.392893 0.245360 +vt 0.375000 0.232017 +vt 0.625000 0.017983 +vt 0.607107 0.004640 +vt 0.555646 0.000000 +vt 0.555646 0.750000 +vt 0.444354 1.000000 +vt 0.625000 0.625000 +vt 0.875000 0.517983 +vt 0.625000 0.517983 +vt 0.125000 0.625000 +vt 0.375000 0.517983 +vt 0.125000 0.517983 +vt 0.607107 0.504640 +vt 0.555646 0.500000 +vt 0.125000 0.732017 +vt 0.375000 0.625000 +vt 0.625000 0.732017 +vt 0.875000 0.625000 +vt 0.444354 0.500000 +vt 0.555646 0.250000 +vt 0.444354 0.250000 +vt 0.444354 0.750000 +vt 0.375000 0.732017 +vt 0.625000 0.232017 +vt 0.375000 0.232017 +vt 0.444354 1.000000 +vt 0.555646 0.750000 +vt 0.375000 0.500000 +vt 0.375000 0.250000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 0.250000 +vt 0.125000 0.750000 +vt 0.375000 0.750000 +vt 0.375000 1.000000 +vt 0.875000 0.732017 +vt 0.625000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 0.500000 +vt 0.125000 0.500000 +vt 0.625000 0.250000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.125000 0.750000 +vt 0.555646 1.000000 +vt 0.625000 0.750000 +vt 0.875000 0.750000 +vt 0.375000 0.017983 +vt 0.555646 0.000000 +vt 0.625000 0.017983 +vt 0.392893 0.504640 +vt 0.607107 0.504640 +vt 0.607107 0.745360 +vt 0.375000 0.125000 +vt 0.625000 0.125000 +vt 0.625000 0.232017 +vt 0.607107 0.245360 +vt 0.444354 0.000000 +vt 0.375000 0.017983 +vt 0.392893 0.004640 +vt 0.375000 0.125000 +vt 0.625000 0.125000 +vt 0.555646 1.000000 +vt 0.392893 0.504640 +vt 0.875000 0.732017 +vt 0.392893 0.745360 +vt 0.607107 0.745360 +vt 0.392893 0.245360 +vt 0.607107 0.245360 +vt 0.125000 0.500000 +vt 0.875000 0.750000 +vt 0.375000 0.250000 +vt 0.625000 1.000000 +vt 0.392893 0.004640 +vt 0.444354 0.000000 +vt 0.607107 0.004640 +vn 0.0000 -0.4580 0.8889 +vn 0.0000 -0.4580 -0.8889 +vn -1.0000 0.0000 0.0000 +vn 1.0000 0.0000 -0.0000 +vn 0.0000 -1.0000 0.0000 +vn -0.8994 -0.4371 0.0000 +vn -0.9357 -0.3420 -0.0865 +vn -0.9600 -0.2798 0.0000 +vn 0.9350 0.0000 -0.3547 +vn 0.9350 0.0000 0.3547 +vn 0.7071 0.0000 -0.7071 +vn 0.7071 0.0000 0.7071 +vn 0.0000 0.0000 1.0000 +vn 0.3547 0.0000 0.9350 +vn -0.3547 0.0000 0.9350 +vn -0.7071 -0.0000 0.7071 +vn -0.8496 0.0000 0.5274 +vn 0.3547 0.0000 -0.9350 +vn 0.3548 0.0000 -0.9350 +vn -0.9350 0.0000 0.3547 +vn -0.9350 0.0000 -0.3547 +vn -0.7071 0.0000 -0.7071 +vn -0.5274 0.0000 -0.8496 +vn 0.9856 0.0000 0.1690 +vn 0.1690 0.0000 0.9856 +vn -0.9856 0.0000 0.1690 +vn 0.3548 0.0000 0.9350 +vn 0.1689 0.0000 0.9856 +vn 0.0000 0.0000 -1.0000 +vn -0.3547 0.0000 -0.9350 +vn 0.9856 0.0000 -0.1690 +vn 0.0000 1.0000 0.0000 +vn -0.9955 -0.0003 0.0951 +vn -0.1017 -0.4249 0.8995 +vn 0.0000 -0.5611 0.8277 +vn -0.0943 -0.6679 0.7382 +vn -0.1007 -0.0002 0.9949 +vn -0.1009 -0.0002 0.9949 +vn 0.9084 -0.4158 -0.0433 +vn 0.8994 -0.4371 0.0000 +vn 0.9600 -0.2798 -0.0000 +vn 0.9955 -0.0003 0.0951 +vn 0.1017 -0.4249 0.8995 +vn 0.0000 -0.3660 0.9306 +vn 0.1007 -0.0002 0.9949 +vn -0.9084 -0.4158 0.0433 +vn -0.9955 -0.0003 -0.0951 +vn -0.1017 -0.4249 -0.8995 +vn 0.0000 -0.5611 -0.8277 +vn 0.0000 -0.3660 -0.9306 +vn -0.1007 -0.0002 -0.9949 +vn 0.9955 -0.0003 -0.0951 +vn 0.1017 -0.4249 -0.8995 +vn 0.0943 -0.6679 -0.7382 +vn 0.1007 -0.0002 -0.9949 +vn 0.1009 -0.0002 -0.9949 +vn -0.5274 0.0000 0.8496 +vn 0.8496 0.0000 0.5274 +vn 0.1689 0.0000 -0.9856 +vn 0.1690 0.0000 -0.9856 +vn -0.9856 0.0000 -0.1690 +vn 0.9357 -0.3420 0.0865 +vn -0.8083 -0.5791 0.1063 +vn -0.7200 -0.6480 0.2484 +vn -0.6739 -0.6722 0.3067 +vn -0.5108 -0.7155 0.4766 +vn -0.4916 -0.7186 0.4919 +vn -0.2874 -0.7133 0.6393 +vn -0.2692 -0.7076 0.6533 +vn -0.9954 -0.0003 0.0956 +vn -0.9275 -0.0010 0.3738 +vn -0.9272 -0.0009 0.3745 +vn -0.7164 -0.0011 0.6977 +vn -0.7161 -0.0011 0.6980 +vn -0.3913 -0.0008 0.9203 +vn -0.3913 -0.0007 0.9203 +vn 0.0943 -0.6679 0.7382 +vn 0.2692 -0.7076 0.6533 +vn 0.2874 -0.7133 0.6393 +vn 0.5108 -0.7155 0.4766 +vn 0.4916 -0.7186 0.4919 +vn 0.6739 -0.6722 0.3067 +vn 0.7200 -0.6480 0.2484 +vn 0.8083 -0.5791 0.1063 +vn 0.1009 -0.0002 0.9949 +vn 0.3913 -0.0007 0.9203 +vn 0.3913 -0.0008 0.9203 +vn 0.7164 -0.0011 0.6977 +vn 0.7161 -0.0011 0.6980 +vn 0.9272 -0.0009 0.3745 +vn 0.9275 -0.0010 0.3738 +vn 0.9954 -0.0003 0.0956 +vn -0.0943 -0.6679 -0.7382 +vn -0.2692 -0.7076 -0.6533 +vn -0.2874 -0.7133 -0.6393 +vn -0.5108 -0.7155 -0.4766 +vn -0.4916 -0.7186 -0.4919 +vn -0.6739 -0.6722 -0.3067 +vn -0.7200 -0.6480 -0.2484 +vn -0.8083 -0.5791 -0.1063 +vn -0.1009 -0.0002 -0.9949 +vn -0.3913 -0.0007 -0.9203 +vn -0.3913 -0.0008 -0.9203 +vn -0.7164 -0.0011 -0.6977 +vn -0.7161 -0.0011 -0.6980 +vn -0.9272 -0.0009 -0.3745 +vn -0.9275 -0.0010 -0.3738 +vn -0.9954 -0.0003 -0.0956 +vn 0.8083 -0.5791 -0.1063 +vn 0.7200 -0.6480 -0.2484 +vn 0.6739 -0.6722 -0.3067 +vn 0.5108 -0.7155 -0.4766 +vn 0.4916 -0.7186 -0.4919 +vn 0.2874 -0.7133 -0.6393 +vn 0.2692 -0.7076 -0.6533 +vn 0.9954 -0.0003 -0.0956 +vn 0.9275 -0.0010 -0.3738 +vn 0.9272 -0.0009 -0.3745 +vn 0.7164 -0.0011 -0.6977 +vn 0.7161 -0.0011 -0.6980 +vn 0.3913 -0.0008 -0.9203 +vn 0.3913 -0.0007 -0.9203 +vn 0.0000 1.0000 -0.0001 +vn 0.6650 -0.7469 0.0047 +vn 0.6878 -0.3941 0.6097 +vn -0.6650 -0.7469 -0.0047 +vn -0.6878 -0.3941 -0.6097 +vn 0.6616 -0.7499 0.0042 +vn 0.6853 -0.3952 0.6117 +vn -0.6616 -0.7499 -0.0042 +vn -0.6853 -0.3952 -0.6117 +vn -0.9948 -0.1005 0.0184 +vn -0.9943 -0.1041 0.0224 +vn 0.9948 -0.1005 0.0184 +vn -0.0981 -0.1586 -0.9825 +vn 0.0000 -0.1682 -0.9858 +vn -0.9948 -0.1005 -0.0184 +vn 0.0981 -0.1586 -0.9825 +vn 0.9948 -0.1005 -0.0184 +vn 0.9943 -0.1041 -0.0224 +vn -0.0981 -0.1586 0.9825 +vn 0.0981 -0.1586 0.9825 +vn 0.0000 -0.1682 0.9858 +vn 0.6618 -0.7497 -0.0042 +vn 0.6648 -0.7470 -0.0047 +vn 0.6650 -0.7469 -0.0047 +vn 0.6854 -0.3952 -0.6116 +vn 0.6876 -0.3941 -0.6098 +vn 0.6878 -0.3941 -0.6097 +vn -0.6854 -0.3952 0.6116 +vn -0.6876 -0.3941 0.6098 +vn -0.6878 -0.3941 0.6097 +vn -0.6618 -0.7497 0.0042 +vn -0.6648 -0.7470 0.0047 +vn -0.6650 -0.7469 0.0047 +vn -0.3720 -0.1634 0.9137 +vn -0.7091 -0.1632 0.6859 +vn -0.6964 -0.1609 0.6994 +vn -0.9117 -0.1413 0.3858 +vn -0.9169 -0.1398 0.3738 +vn -0.9715 -0.1231 0.2026 +vn -0.9728 -0.1231 0.1960 +vn 0.9169 -0.1398 0.3738 +vn 0.9821 -0.1180 0.1465 +vn 0.9117 -0.1413 0.3858 +vn 0.6964 -0.1609 0.6994 +vn 0.7091 -0.1632 0.6859 +vn 0.3720 -0.1634 0.9137 +vn -0.9169 -0.1398 -0.3738 +vn -0.9821 -0.1180 -0.1465 +vn -0.9117 -0.1413 -0.3858 +vn -0.6964 -0.1609 -0.6994 +vn -0.7091 -0.1632 -0.6859 +vn -0.3720 -0.1634 -0.9137 +vn 0.3720 -0.1634 -0.9137 +vn 0.7091 -0.1632 -0.6859 +vn 0.6964 -0.1609 -0.6994 +vn 0.9117 -0.1413 -0.3858 +vn 0.9169 -0.1398 -0.3738 +vn 0.9715 -0.1231 -0.2026 +vn 0.9728 -0.1231 -0.1960 +vn -0.9925 -0.1224 0.0000 +vn 0.9925 -0.1224 -0.0000 +vn 0.6616 -0.7499 -0.0042 +vn 0.6853 -0.3952 -0.6117 +vn -0.6853 -0.3952 0.6117 +vn -0.6616 -0.7499 0.0042 +vn -0.4099 -0.1646 0.8972 +vn 0.4099 -0.1646 0.8972 +vn -0.4099 -0.1646 -0.8972 +vn 0.4099 -0.1646 -0.8972 +vn -0.3572 0.0000 -0.9340 +vn -0.5288 0.0000 -0.8487 +vn -0.3539 0.0000 -0.9353 +vn -0.5268 -0.0000 -0.8500 +vn -0.5268 -0.0000 0.8500 +vn -0.5278 -0.0000 0.8494 +vn 0.9350 0.0000 0.3548 +vn -0.3539 0.0000 0.9353 +vn -0.3555 0.0000 0.9347 +vn 0.0000 -0.9445 -0.3284 +vn 0.0000 -0.3284 -0.9445 +vn 0.0000 0.9445 -0.3284 +vn 0.0000 0.3284 -0.9445 +vn 0.0000 -0.9445 0.3284 +vn 0.0000 -0.3284 0.9445 +vn 0.0000 0.9445 0.3284 +vn 0.0000 0.3284 0.9445 +usemtl WhiteSurface +s off +f 4/1/1 821/2/1 815/3/1 +f 1/4/2 827/5/2 828/6/2 +f 2/7/1 824/8/1 811/9/1 +f 2/7/3 811/9/3 810/10/3 +f 3/11/4 806/12/4 808/13/4 +f 816/14/5 813/15/5 3/11/5 +f 1/4/5 828/16/5 830/17/5 +f 3/11/2 818/18/2 806/12/2 +f 4/1/1 807/19/1 821/2/1 +f 1/4/2 809/20/2 827/5/2 +f 2/7/1 823/21/1 824/8/1 +f 810/10/3 809/20/3 1/4/3 +f 1/4/3 2/7/3 810/10/3 +f 808/13/4 807/19/4 4/1/4 +f 4/1/4 3/11/4 808/13/4 +f 3/11/5 4/1/5 816/14/5 +f 4/1/5 815/22/5 816/14/5 +f 823/23/5 2/7/5 830/17/5 +f 2/7/5 1/4/5 830/17/5 +f 3/11/2 813/24/2 818/18/2 +s 1 +f 612/25/6 877/26/7 611/27/8 +f 54/28/4 52/29/9 51/30/9 +f 55/31/4 53/32/9 52/29/9 +f 57/33/10 55/31/4 54/28/4 +f 58/34/10 56/35/4 55/31/4 +f 48/36/9 15/37/11 9/38/11 +f 51/30/9 16/39/11 15/37/11 +f 52/29/9 17/40/11 16/39/11 +f 53/32/9 774/41/11 17/40/11 +f 56/35/4 775/42/9 53/32/9 +f 59/43/10 779/44/4 56/35/4 +f 38/45/12 780/46/10 59/43/10 +f 39/47/12 59/43/10 58/34/10 +f 40/48/12 58/34/10 57/33/10 +f 10/49/12 57/33/10 50/50/10 +f 50/50/10 54/28/4 49/51/4 +f 49/51/4 51/30/9 48/36/9 +f 63/52/13 61/53/14 60/54/14 +f 64/55/13 62/56/14 61/53/14 +f 66/57/15 64/55/13 63/52/13 +f 67/58/15 65/59/13 64/55/13 +f 45/60/14 40/48/12 10/49/12 +f 60/54/14 39/47/12 40/48/12 +f 61/53/14 38/45/12 39/47/12 +f 62/56/14 799/61/12 38/45/12 +f 65/59/13 803/62/14 62/56/14 +f 68/63/15 805/64/13 65/59/13 +f 41/65/16 802/66/15 68/63/15 +f 42/67/16 68/63/15 67/58/15 +f 43/68/16 67/58/15 66/57/15 +f 11/69/16 66/57/15 47/70/15 +f 47/70/15 63/52/13 46/71/13 +f 46/71/13 60/54/14 45/60/14 +f 794/72/17 43/68/16 11/69/16 +f 793/73/17 42/67/16 43/68/16 +f 42/67/16 791/74/17 41/65/16 +f 791/74/17 795/75/16 41/65/16 +f 17/76/11 757/77/18 71/78/19 +f 16/79/11 71/78/19 70/80/18 +f 15/81/11 70/80/18 69/82/19 +f 9/83/11 69/82/19 44/84/18 +f 160/85/13 158/86/14 157/87/14 +f 161/88/13 159/89/14 158/86/14 +f 163/90/15 161/88/13 160/85/13 +f 164/91/15 162/92/13 161/88/13 +f 154/93/14 144/94/12 116/95/12 +f 157/87/14 143/96/12 144/94/12 +f 158/86/14 142/97/12 143/96/12 +f 142/97/12 801/98/14 785/99/12 +f 162/92/13 801/98/14 159/89/14 +f 165/100/15 804/101/13 162/92/13 +f 145/102/16 800/103/15 165/100/15 +f 146/104/16 165/100/15 164/91/15 +f 147/105/16 164/91/15 163/90/15 +f 117/106/16 163/90/15 156/107/15 +f 156/107/15 160/85/13 155/108/13 +f 155/108/13 157/87/14 154/93/14 +f 169/109/3 167/110/20 166/111/20 +f 170/112/3 168/113/20 167/110/20 +f 172/114/21 170/112/3 169/109/3 +f 173/115/21 171/116/3 170/112/3 +f 151/117/20 147/105/16 117/106/16 +f 166/111/20 146/104/16 147/105/16 +f 167/110/20 145/102/16 146/104/16 +f 168/113/20 781/118/16 145/102/16 +f 171/116/3 777/119/20 168/113/20 +f 174/120/21 776/121/3 171/116/3 +f 148/122/22 723/123/21 174/120/21 +f 149/124/22 174/120/21 173/115/21 +f 150/125/22 173/115/21 172/114/21 +f 118/126/22 172/114/21 153/127/21 +f 153/127/21 169/109/3 152/128/3 +f 152/128/3 166/111/20 151/117/20 +f 725/129/23 150/125/22 118/126/22 +f 724/130/23 149/124/22 150/125/22 +f 726/131/23 148/122/22 149/124/22 +f 737/132/23 722/133/22 148/122/22 +f 256/134/4 254/135/9 253/136/9 +f 257/137/4 255/138/9 254/135/9 +f 259/139/10 257/137/4 256/134/4 +f 260/140/10 258/141/4 257/137/4 +f 250/142/9 223/143/11 218/144/11 +f 253/136/9 224/145/11 223/143/11 +f 254/135/9 225/146/11 224/145/11 +f 255/138/9 719/147/11 225/146/11 +f 258/141/4 717/148/9 255/138/9 +f 261/149/10 720/150/10 721/151/24 +f 245/152/12 720/150/10 261/149/10 +f 246/153/12 261/149/10 260/140/10 +f 247/154/12 260/140/10 259/139/10 +f 219/155/12 259/139/10 252/156/10 +f 252/156/10 256/134/4 251/157/4 +f 251/157/4 253/136/9 250/142/9 +f 262/158/14 772/159/25 263/160/14 +f 772/159/25 264/161/14 263/160/14 +f 249/162/14 247/154/12 219/155/12 +f 262/158/14 246/153/12 247/154/12 +f 263/160/14 245/152/12 246/153/12 +f 264/161/14 773/163/12 245/152/12 +f 769/164/25 767/165/14 264/161/14 +f 249/162/14 766/166/25 262/158/14 +f 225/167/11 708/168/18 267/169/18 +f 224/170/11 267/169/18 266/171/18 +f 223/172/11 266/171/18 265/173/18 +f 218/174/11 265/173/18 248/175/18 +f 346/176/3 344/177/20 343/178/20 +f 347/179/3 345/180/20 344/177/20 +f 349/181/21 347/179/3 346/176/3 +f 350/182/21 348/183/3 347/179/3 +f 340/184/20 336/185/16 310/186/16 +f 343/178/20 335/187/16 336/185/16 +f 344/177/20 334/188/16 335/187/16 +f 345/180/20 732/189/16 334/188/16 +f 348/183/3 670/190/3 669/191/26 +f 351/192/21 670/190/3 348/183/3 +f 337/193/22 672/194/21 351/192/21 +f 338/195/22 351/192/21 350/182/21 +f 339/196/22 350/182/21 349/181/21 +f 311/197/22 349/181/21 342/198/21 +f 342/198/21 346/176/3 341/199/3 +f 341/199/3 343/178/20 340/184/20 +f 675/200/23 339/196/22 311/197/22 +f 674/201/23 338/195/22 339/196/22 +f 679/202/23 337/193/22 338/195/22 +f 680/203/23 673/204/22 337/193/22 +f 438/205/4 436/206/9 435/207/9 +f 439/208/4 437/209/9 436/206/9 +f 441/210/10 439/208/4 438/205/4 +f 442/211/10 440/212/4 439/208/4 +f 432/213/9 398/214/11 392/215/11 +f 435/207/9 399/216/11 398/214/11 +f 436/206/9 400/217/11 399/216/11 +f 437/209/9 665/218/11 400/217/11 +f 440/212/4 668/219/9 437/209/9 +f 443/220/10 667/221/4 440/212/4 +f 421/222/12 666/223/10 443/220/10 +f 422/224/12 443/220/10 442/211/10 +f 423/225/12 442/211/10 441/210/10 +f 393/226/12 441/210/10 434/227/10 +f 434/227/10 438/205/4 433/228/4 +f 433/228/4 435/207/9 432/213/9 +f 715/229/25 445/230/14 444/231/27 +f 713/232/28 446/233/27 445/230/14 +f 431/234/27 423/225/12 393/226/12 +f 444/231/27 422/224/12 423/225/12 +f 445/230/14 421/222/12 422/224/12 +f 446/233/27 663/235/12 421/222/12 +f 710/236/25 712/237/14 446/233/27 +f 716/238/25 444/231/27 431/234/27 +f 424/239/22 650/240/21 449/241/21 +f 425/242/22 449/241/21 448/243/21 +f 426/244/22 448/243/21 447/245/21 +f 394/246/22 447/245/21 430/247/21 +f 453/248/29 451/249/30 450/250/30 +f 454/251/29 452/252/30 451/249/30 +f 456/253/18 454/251/29 453/248/29 +f 457/254/18 455/255/29 454/251/29 +f 427/256/30 426/244/22 394/246/22 +f 450/250/30 425/242/22 426/244/22 +f 451/249/30 424/239/22 425/242/22 +f 424/239/22 660/257/30 661/258/22 +f 452/252/30 662/259/29 660/257/30 +f 455/255/29 664/260/18 662/259/29 +f 458/261/18 665/262/11 664/260/18 +f 399/263/11 458/261/18 457/254/18 +f 398/264/11 457/254/18 456/253/18 +f 392/265/11 456/253/18 429/266/18 +f 429/266/18 453/248/29 428/267/29 +f 428/267/29 450/250/30 427/256/30 +f 546/268/9 642/269/31 547/270/9 +f 547/270/9 639/271/31 548/272/9 +f 545/273/9 510/274/11 504/275/11 +f 546/268/9 511/276/11 510/274/11 +f 547/270/9 512/277/11 511/276/11 +f 548/272/9 636/278/11 512/277/11 +f 548/272/9 640/279/31 641/280/9 +f 644/281/31 546/268/9 545/273/9 +f 552/282/3 550/283/20 549/284/20 +f 553/285/3 551/286/20 550/283/20 +f 555/287/21 553/285/3 552/282/3 +f 556/288/21 554/289/3 553/285/3 +f 542/290/20 535/291/16 505/292/16 +f 549/284/20 534/293/16 535/291/16 +f 550/283/20 533/294/16 534/293/16 +f 551/286/20 628/295/16 533/294/16 +f 554/289/3 625/296/20 551/286/20 +f 557/297/21 624/298/3 554/289/3 +f 536/299/22 626/300/21 557/297/21 +f 537/301/22 557/297/21 556/288/21 +f 538/302/22 556/288/21 555/287/21 +f 506/303/22 555/287/21 544/304/21 +f 544/304/21 552/282/3 543/305/3 +f 543/305/3 549/284/20 542/290/20 +f 561/306/29 559/307/30 558/308/30 +f 562/309/29 560/310/30 559/307/30 +f 564/311/18 562/309/29 561/306/29 +f 565/312/18 563/313/29 562/309/29 +f 539/314/30 538/302/22 506/303/22 +f 558/308/30 537/301/22 538/302/22 +f 559/307/30 536/299/22 537/301/22 +f 560/310/30 627/315/22 536/299/22 +f 563/313/29 629/316/30 560/310/30 +f 566/317/18 630/318/29 563/313/29 +f 512/319/11 635/320/18 566/317/18 +f 511/321/11 566/317/18 565/312/18 +f 510/322/11 565/312/18 564/311/18 +f 504/323/11 564/311/18 541/324/18 +f 541/324/18 561/306/29 540/325/29 +f 540/325/29 558/308/30 539/314/30 +f 665/326/32 668/327/32 850/328/32 +f 843/329/33 613/330/3 612/25/3 +f 837/331/34 609/332/35 842/333/36 +f 842/333/37 610/334/13 848/335/38 +f 898/336/39 619/337/40 617/338/41 +f 870/339/32 626/340/32 627/341/32 +f 620/342/4 862/343/42 619/337/4 +f 858/344/43 609/332/35 608/345/44 +f 863/346/45 610/334/13 609/332/13 +f 838/347/46 612/25/6 611/27/8 +f 891/348/32 779/349/32 780/350/32 +f 613/330/3 882/351/47 612/25/3 +f 878/352/48 618/353/49 616/354/50 +f 883/355/51 621/356/29 618/353/29 +f 910/357/32 781/358/32 777/359/32 +f 903/360/52 620/342/4 619/337/4 +f 897/361/53 618/353/49 902/362/54 +f 902/362/55 621/356/29 908/363/56 +f 534/293/16 684/364/57 686/365/57 +f 116/95/12 789/366/58 790/367/58 +f 787/368/58 785/99/12 786/369/58 +f 69/82/19 760/370/59 761/371/60 +f 70/80/18 759/372/60 760/370/59 +f 730/373/57 732/189/16 731/374/57 +f 535/291/16 686/365/57 687/375/57 +f 71/78/19 758/376/59 759/372/60 +f 265/173/18 701/377/60 702/378/60 +f 505/292/16 687/375/57 634/379/57 +f 335/187/16 730/373/57 733/380/57 +f 143/96/12 787/368/58 788/381/58 +f 448/243/21 651/382/61 652/383/61 +f 447/245/21 652/383/61 653/384/61 +f 706/385/60 708/168/18 707/386/60 +f 533/294/16 685/387/57 684/364/57 +f 336/185/16 733/380/57 734/388/57 +f 144/94/12 788/381/58 789/366/58 +f 44/84/18 761/371/60 762/389/59 +f 266/171/18 706/385/60 701/377/60 +f 248/175/18 702/378/60 704/390/60 +f 310/186/16 734/388/57 735/391/57 +f 430/247/21 653/384/61 654/392/61 +f 449/241/21 649/393/61 651/382/61 +f 619/337/40 857/394/62 617/338/41 +f 843/329/63 841/395/64 846/396/65 +f 846/396/65 840/397/66 845/398/67 +f 840/397/66 844/399/68 845/398/67 +f 839/400/69 842/333/36 844/399/68 +f 847/401/70 846/396/71 849/402/72 +f 849/402/72 845/398/73 850/328/74 +f 845/398/73 851/403/75 850/328/74 +f 844/399/76 848/335/38 851/403/75 +f 863/346/77 861/404/78 866/405/79 +f 866/405/79 860/406/80 865/407/81 +f 860/406/80 864/408/82 865/407/81 +f 859/409/83 862/343/84 864/408/82 +f 867/410/85 866/405/86 869/411/87 +f 869/411/87 865/407/88 870/339/89 +f 865/407/88 871/412/90 870/339/89 +f 864/408/91 868/413/92 871/412/90 +f 883/355/93 881/414/94 886/415/95 +f 886/415/95 880/416/96 885/417/97 +f 880/416/96 884/418/98 885/417/97 +f 879/419/99 882/351/100 884/418/98 +f 887/420/101 886/415/102 889/421/103 +f 889/421/103 885/417/104 890/422/105 +f 885/417/104 891/348/106 890/422/105 +f 884/418/107 888/423/108 891/348/106 +f 903/360/109 901/424/110 906/425/111 +f 906/425/111 900/426/112 905/427/113 +f 900/426/112 904/428/114 905/427/113 +f 899/429/115 902/362/54 904/428/114 +f 907/430/116 906/425/117 909/431/118 +f 909/431/118 905/427/119 910/357/120 +f 905/427/119 911/432/121 910/357/120 +f 904/428/122 908/363/56 911/432/121 +f 612/25/6 882/351/100 877/26/7 +f 54/28/4 55/31/4 52/29/9 +f 55/31/4 56/35/4 53/32/9 +f 57/33/10 58/34/10 55/31/4 +f 58/34/10 59/43/10 56/35/4 +f 48/36/9 51/30/9 15/37/11 +f 51/30/9 52/29/9 16/39/11 +f 52/29/9 53/32/9 17/40/11 +f 53/32/9 775/42/9 774/41/11 +f 56/35/4 779/44/4 775/42/9 +f 59/43/10 780/46/10 779/44/4 +f 38/45/12 799/61/12 780/46/10 +f 39/47/12 38/45/12 59/43/10 +f 40/48/12 39/47/12 58/34/10 +f 10/49/12 40/48/12 57/33/10 +f 50/50/10 57/33/10 54/28/4 +f 49/51/4 54/28/4 51/30/9 +f 63/52/13 64/55/13 61/53/14 +f 64/55/13 65/59/13 62/56/14 +f 66/57/15 67/58/15 64/55/13 +f 67/58/15 68/63/15 65/59/13 +f 45/60/14 60/54/14 40/48/12 +f 60/54/14 61/53/14 39/47/12 +f 61/53/14 62/56/14 38/45/12 +f 62/56/14 803/62/14 799/61/12 +f 65/59/13 805/64/13 803/62/14 +f 68/63/15 802/66/15 805/64/13 +f 41/65/16 795/75/16 802/66/15 +f 42/67/16 41/65/16 68/63/15 +f 43/68/16 42/67/16 67/58/15 +f 11/69/16 43/68/16 66/57/15 +f 47/70/15 66/57/15 63/52/13 +f 46/71/13 63/52/13 60/54/14 +f 794/72/17 793/73/17 43/68/16 +f 793/73/17 792/433/17 42/67/16 +f 42/67/16 792/433/17 791/74/17 +f 791/74/17 796/434/17 795/75/16 +f 17/76/11 774/435/11 757/77/18 +f 16/79/11 17/76/11 71/78/19 +f 15/81/11 16/79/11 70/80/18 +f 9/83/11 15/81/11 69/82/19 +f 160/85/13 161/88/13 158/86/14 +f 161/88/13 162/92/13 159/89/14 +f 163/90/15 164/91/15 161/88/13 +f 164/91/15 165/100/15 162/92/13 +f 154/93/14 157/87/14 144/94/12 +f 157/87/14 158/86/14 143/96/12 +f 158/86/14 159/89/14 142/97/12 +f 142/97/12 159/89/14 801/98/14 +f 162/92/13 804/101/13 801/98/14 +f 165/100/15 800/103/15 804/101/13 +f 145/102/16 781/118/16 800/103/15 +f 146/104/16 145/102/16 165/100/15 +f 147/105/16 146/104/16 164/91/15 +f 117/106/16 147/105/16 163/90/15 +f 156/107/15 163/90/15 160/85/13 +f 155/108/13 160/85/13 157/87/14 +f 169/109/3 170/112/3 167/110/20 +f 170/112/3 171/116/3 168/113/20 +f 172/114/21 173/115/21 170/112/3 +f 173/115/21 174/120/21 171/116/3 +f 151/117/20 166/111/20 147/105/16 +f 166/111/20 167/110/20 146/104/16 +f 167/110/20 168/113/20 145/102/16 +f 168/113/20 777/119/20 781/118/16 +f 171/116/3 776/121/3 777/119/20 +f 174/120/21 723/123/21 776/121/3 +f 148/122/22 722/133/22 723/123/21 +f 149/124/22 148/122/22 174/120/21 +f 150/125/22 149/124/22 173/115/21 +f 118/126/22 150/125/22 172/114/21 +f 153/127/21 172/114/21 169/109/3 +f 152/128/3 169/109/3 166/111/20 +f 725/129/23 724/130/23 150/125/22 +f 724/130/23 726/131/23 149/124/22 +f 726/131/23 737/132/23 148/122/22 +f 737/132/23 736/436/23 722/133/22 +f 256/134/4 257/137/4 254/135/9 +f 257/137/4 258/141/4 255/138/9 +f 259/139/10 260/140/10 257/137/4 +f 260/140/10 261/149/10 258/141/4 +f 250/142/9 253/136/9 223/143/11 +f 253/136/9 254/135/9 224/145/11 +f 254/135/9 255/138/9 225/146/11 +f 255/138/9 717/148/9 719/147/11 +f 258/141/4 718/437/4 717/148/9 +f 718/437/4 258/141/4 721/151/24 +f 258/141/4 261/149/10 721/151/24 +f 245/152/12 773/163/12 720/150/10 +f 246/153/12 245/152/12 261/149/10 +f 247/154/12 246/153/12 260/140/10 +f 219/155/12 247/154/12 259/139/10 +f 252/156/10 259/139/10 256/134/4 +f 251/157/4 256/134/4 253/136/9 +f 262/158/14 766/166/25 772/159/25 +f 772/159/25 769/164/25 264/161/14 +f 249/162/14 262/158/14 247/154/12 +f 262/158/14 263/160/14 246/153/12 +f 263/160/14 264/161/14 245/152/12 +f 264/161/14 767/165/14 773/163/12 +f 769/164/25 768/438/25 767/165/14 +f 249/162/14 765/439/25 766/166/25 +f 225/167/11 719/440/11 708/168/18 +f 224/170/11 225/167/11 267/169/18 +f 223/172/11 224/170/11 266/171/18 +f 218/174/11 223/172/11 265/173/18 +f 346/176/3 347/179/3 344/177/20 +f 347/179/3 348/183/3 345/180/20 +f 349/181/21 350/182/21 347/179/3 +f 350/182/21 351/192/21 348/183/3 +f 340/184/20 343/178/20 336/185/16 +f 343/178/20 344/177/20 335/187/16 +f 344/177/20 345/180/20 334/188/16 +f 345/180/20 671/441/20 732/189/16 +f 671/441/20 345/180/20 669/191/26 +f 345/180/20 348/183/3 669/191/26 +f 351/192/21 672/194/21 670/190/3 +f 337/193/22 673/204/22 672/194/21 +f 338/195/22 337/193/22 351/192/21 +f 339/196/22 338/195/22 350/182/21 +f 311/197/22 339/196/22 349/181/21 +f 342/198/21 349/181/21 346/176/3 +f 341/199/3 346/176/3 343/178/20 +f 675/200/23 674/201/23 339/196/22 +f 674/201/23 679/202/23 338/195/22 +f 679/202/23 680/203/23 337/193/22 +f 680/203/23 681/442/23 673/204/22 +f 438/205/4 439/208/4 436/206/9 +f 439/208/4 440/212/4 437/209/9 +f 441/210/10 442/211/10 439/208/4 +f 442/211/10 443/220/10 440/212/4 +f 432/213/9 435/207/9 398/214/11 +f 435/207/9 436/206/9 399/216/11 +f 436/206/9 437/209/9 400/217/11 +f 437/209/9 668/219/9 665/218/11 +f 440/212/4 667/221/4 668/219/9 +f 443/220/10 666/223/10 667/221/4 +f 421/222/12 663/235/12 666/223/10 +f 422/224/12 421/222/12 443/220/10 +f 423/225/12 422/224/12 442/211/10 +f 393/226/12 423/225/12 441/210/10 +f 434/227/10 441/210/10 438/205/4 +f 433/228/4 438/205/4 435/207/9 +f 715/229/25 713/232/28 445/230/14 +f 713/232/28 710/236/25 446/233/27 +f 431/234/27 444/231/27 423/225/12 +f 444/231/27 445/230/14 422/224/12 +f 445/230/14 446/233/27 421/222/12 +f 446/233/27 712/237/14 663/235/12 +f 710/236/25 711/443/28 712/237/14 +f 716/238/25 715/229/25 444/231/27 +f 424/239/22 661/258/22 650/240/21 +f 425/242/22 424/239/22 449/241/21 +f 426/244/22 425/242/22 448/243/21 +f 394/246/22 426/244/22 447/245/21 +f 453/248/29 454/251/29 451/249/30 +f 454/251/29 455/255/29 452/252/30 +f 456/253/18 457/254/18 454/251/29 +f 457/254/18 458/261/18 455/255/29 +f 427/256/30 450/250/30 426/244/22 +f 450/250/30 451/249/30 425/242/22 +f 451/249/30 452/252/30 424/239/22 +f 424/239/22 452/252/30 660/257/30 +f 452/252/30 455/255/29 662/259/29 +f 455/255/29 458/261/18 664/260/18 +f 458/261/18 400/444/11 665/262/11 +f 399/263/11 400/444/11 458/261/18 +f 398/264/11 399/263/11 457/254/18 +f 392/265/11 398/264/11 456/253/18 +f 429/266/18 456/253/18 453/248/29 +f 428/267/29 453/248/29 450/250/30 +f 546/268/9 643/445/31 642/269/31 +f 547/270/9 642/269/31 639/271/31 +f 545/273/9 546/268/9 510/274/11 +f 546/268/9 547/270/9 511/276/11 +f 547/270/9 548/272/9 512/277/11 +f 548/272/9 641/280/9 636/278/11 +f 548/272/9 639/271/31 640/279/31 +f 644/281/31 643/445/31 546/268/9 +f 552/282/3 553/285/3 550/283/20 +f 553/285/3 554/289/3 551/286/20 +f 555/287/21 556/288/21 553/285/3 +f 556/288/21 557/297/21 554/289/3 +f 542/290/20 549/284/20 535/291/16 +f 549/284/20 550/283/20 534/293/16 +f 550/283/20 551/286/20 533/294/16 +f 551/286/20 625/296/20 628/295/16 +f 554/289/3 624/298/3 625/296/20 +f 557/297/21 626/300/21 624/298/3 +f 536/299/22 627/315/22 626/300/21 +f 537/301/22 536/299/22 557/297/21 +f 538/302/22 537/301/22 556/288/21 +f 506/303/22 538/302/22 555/287/21 +f 544/304/21 555/287/21 552/282/3 +f 543/305/3 552/282/3 549/284/20 +f 561/306/29 562/309/29 559/307/30 +f 562/309/29 563/313/29 560/310/30 +f 564/311/18 565/312/18 562/309/29 +f 565/312/18 566/317/18 563/313/29 +f 539/314/30 558/308/30 538/302/22 +f 558/308/30 559/307/30 537/301/22 +f 559/307/30 560/310/30 536/299/22 +f 560/310/30 629/316/30 627/315/22 +f 563/313/29 630/318/29 629/316/30 +f 566/317/18 635/320/18 630/318/29 +f 512/319/11 636/446/11 635/320/18 +f 511/321/11 512/319/11 566/317/18 +f 510/322/11 511/321/11 565/312/18 +f 504/323/11 510/322/11 564/311/18 +f 541/324/18 564/311/18 561/306/29 +f 540/325/29 561/306/29 558/308/30 +f 613/330/32 847/401/32 708/447/32 +f 847/401/32 849/402/32 667/448/32 +f 849/402/32 850/328/32 668/327/32 +f 850/328/32 851/403/32 664/449/32 +f 849/402/32 668/327/32 667/448/32 +f 851/403/32 848/450/32 662/451/32 +f 848/450/32 610/452/32 650/453/32 +f 660/454/32 848/450/32 661/455/32 +f 610/452/32 623/456/32 650/453/32 +f 623/456/32 649/457/32 650/453/32 +f 847/401/32 667/448/32 666/458/32 +f 718/459/32 721/460/32 613/330/32 +f 717/461/32 718/459/32 613/330/32 +f 650/453/32 661/455/32 848/450/32 +f 719/462/32 717/461/32 613/330/32 +f 711/463/32 707/464/32 708/447/32 +f 708/447/32 719/462/32 613/330/32 +f 848/450/32 660/454/32 662/451/32 +f 711/463/32 708/447/32 712/465/32 +f 712/465/32 708/447/32 847/401/32 +f 851/403/32 662/451/32 664/449/32 +f 664/449/32 665/326/32 850/328/32 +f 663/466/32 712/465/32 847/401/32 +f 666/458/32 663/466/32 847/401/32 +f 843/329/33 847/401/70 613/330/3 +f 837/331/34 608/345/44 609/332/35 +f 842/333/37 609/332/13 610/334/13 +f 898/336/39 903/360/109 619/337/40 +f 620/342/32 669/467/32 670/468/32 +f 620/342/32 670/468/32 672/469/32 +f 871/412/32 868/413/32 624/470/32 +f 868/413/32 620/342/32 681/471/32 +f 624/470/32 868/413/32 625/472/32 +f 869/411/32 870/339/32 629/473/32 +f 870/339/32 871/412/32 626/340/32 +f 626/340/32 871/412/32 624/470/32 +f 610/452/32 867/474/32 641/475/32 +f 867/474/32 869/411/32 630/476/32 +f 635/477/32 867/474/32 630/476/32 +f 640/478/32 623/456/32 641/475/32 +f 623/456/32 610/452/32 641/475/32 +f 620/342/32 672/469/32 673/479/32 +f 673/479/32 681/471/32 620/342/32 +f 681/471/32 685/480/32 868/413/32 +f 685/480/32 628/481/32 868/413/32 +f 636/482/32 641/475/32 867/474/32 +f 635/477/32 636/482/32 867/474/32 +f 628/481/32 625/472/32 868/413/32 +f 629/473/32 630/476/32 869/411/32 +f 627/341/32 629/473/32 870/339/32 +f 620/342/4 868/413/92 862/343/42 +f 858/344/43 863/346/77 609/332/35 +f 863/346/45 867/410/85 610/334/13 +f 838/347/46 843/329/63 612/25/6 +f 888/423/32 613/330/32 767/483/32 +f 613/330/32 721/460/32 720/484/32 +f 613/330/32 720/484/32 773/485/32 +f 890/422/32 891/348/32 780/350/32 +f 891/348/32 888/423/32 779/349/32 +f 779/349/32 888/423/32 775/486/32 +f 887/487/32 889/421/32 805/488/32 +f 889/421/32 890/422/32 803/489/32 +f 887/487/32 805/488/32 802/490/32 +f 622/491/32 621/492/32 796/493/32 +f 621/492/32 887/487/32 796/493/32 +f 796/493/32 887/487/32 795/494/32 +f 802/490/32 795/494/32 887/487/32 +f 613/330/32 773/485/32 767/483/32 +f 805/488/32 889/421/32 803/489/32 +f 888/423/32 767/483/32 757/495/32 +f 775/486/32 888/423/32 774/496/32 +f 767/483/32 768/497/32 758/498/32 +f 767/483/32 758/498/32 757/495/32 +f 799/499/32 803/489/32 890/422/32 +f 757/495/32 774/496/32 888/423/32 +f 780/350/32 799/499/32 890/422/32 +f 613/330/3 888/423/108 882/351/47 +f 878/352/48 883/355/93 618/353/49 +f 883/355/51 887/420/101 621/356/29 +f 669/467/32 620/342/32 671/500/32 +f 620/342/32 907/430/32 731/501/32 +f 671/500/32 620/342/32 732/502/32 +f 907/430/32 909/431/32 776/503/32 +f 909/431/32 910/357/32 777/359/32 +f 907/430/32 776/503/32 723/504/32 +f 910/357/32 911/432/32 800/505/32 +f 911/432/32 908/506/32 804/507/32 +f 804/507/32 908/506/32 801/508/32 +f 908/506/32 621/492/32 786/509/32 +f 621/492/32 622/491/32 786/509/32 +f 908/506/32 786/509/32 785/510/32 +f 785/510/32 801/508/32 908/506/32 +f 732/502/32 620/342/32 731/501/32 +f 911/432/32 804/507/32 800/505/32 +f 736/511/32 731/501/32 907/430/32 +f 722/512/32 736/511/32 907/430/32 +f 910/357/32 800/505/32 781/358/32 +f 723/504/32 722/512/32 907/430/32 +f 776/503/32 909/431/32 777/359/32 +f 903/360/52 907/430/116 620/342/4 +f 897/361/53 616/354/50 618/353/49 +f 902/362/55 618/353/29 621/356/29 +f 534/293/16 533/294/16 684/364/57 +f 116/95/12 144/94/12 789/366/58 +f 787/368/58 142/97/12 785/99/12 +f 69/82/19 70/80/18 760/370/59 +f 70/80/18 71/78/19 759/372/60 +f 730/373/57 334/188/16 732/189/16 +f 535/291/16 534/293/16 686/365/57 +f 71/78/19 757/77/18 758/376/59 +f 265/173/18 266/171/18 701/377/60 +f 505/292/16 535/291/16 687/375/57 +f 335/187/16 334/188/16 730/373/57 +f 143/96/12 142/97/12 787/368/58 +f 448/243/21 449/241/21 651/382/61 +f 447/245/21 448/243/21 652/383/61 +f 706/385/60 267/169/18 708/168/18 +f 533/294/16 628/295/16 685/387/57 +f 336/185/16 335/187/16 733/380/57 +f 144/94/12 143/96/12 788/381/58 +f 44/84/18 69/82/19 761/371/60 +f 266/171/18 267/169/18 706/385/60 +f 248/175/18 265/173/18 702/378/60 +f 310/186/16 336/185/16 734/388/57 +f 430/247/21 447/245/21 653/384/61 +f 449/241/21 650/240/21 649/393/61 +f 619/337/40 862/343/84 857/394/62 +f 843/329/63 838/347/46 841/395/64 +f 846/396/65 841/395/64 840/397/66 +f 840/397/66 839/400/69 844/399/68 +f 839/400/69 837/331/34 842/333/36 +f 847/401/70 843/329/33 846/396/71 +f 849/402/72 846/396/71 845/398/73 +f 845/398/73 844/399/76 851/403/75 +f 844/399/76 842/333/37 848/335/38 +f 863/346/77 858/344/43 861/404/78 +f 866/405/79 861/404/78 860/406/80 +f 860/406/80 859/409/83 864/408/82 +f 859/409/83 857/394/62 862/343/84 +f 867/410/85 863/346/45 866/405/86 +f 869/411/87 866/405/86 865/407/88 +f 865/407/88 864/408/91 871/412/90 +f 864/408/91 862/343/42 868/413/92 +f 883/355/93 878/352/48 881/414/94 +f 886/415/95 881/414/94 880/416/96 +f 880/416/96 879/419/99 884/418/98 +f 879/419/99 877/26/7 882/351/100 +f 887/420/101 883/355/51 886/415/102 +f 889/421/103 886/415/102 885/417/104 +f 885/417/104 884/418/107 891/348/106 +f 884/418/107 882/351/47 888/423/108 +f 903/360/109 898/336/39 901/424/110 +f 906/425/111 901/424/110 900/426/112 +f 900/426/112 899/429/115 904/428/114 +f 899/429/115 897/361/53 902/362/54 +f 907/430/116 903/360/52 906/425/117 +f 909/431/118 906/425/117 905/427/119 +f 905/427/119 904/428/122 911/432/121 +f 904/428/122 902/362/55 908/363/56 +usemtl Felt +s off +f 638/513/32 683/514/32 682/515/32 +f 782/516/13 790/517/13 622/518/13 +f 655/519/29 654/520/29 623/521/29 +f 715/522/4 704/523/4 702/524/4 +f 770/525/4 764/526/4 763/527/4 +f 727/528/3 728/529/3 742/530/3 +f 677/531/3 632/532/3 631/533/3 +f 783/534/32 798/535/32 784/536/32 +f 783/534/123 784/536/123 778/537/123 +f 784/536/32 749/538/32 778/537/32 +f 778/537/32 749/538/32 748/539/32 +f 749/538/32 750/540/32 748/539/32 +f 748/539/32 750/540/32 747/541/32 +f 750/540/32 751/542/32 747/541/32 +f 747/541/32 751/542/32 744/543/32 +f 751/542/32 753/544/32 752/545/32 +f 744/543/32 751/542/32 752/545/32 +f 754/546/32 764/547/32 771/548/32 +f 753/544/32 754/546/32 756/549/32 +f 743/550/32 744/543/32 746/551/32 +f 753/544/32 756/549/32 752/545/32 +f 754/546/32 771/548/32 755/552/32 +f 754/546/32 755/552/32 756/549/32 +f 738/553/32 743/550/32 745/554/32 +f 742/530/32 728/529/32 729/555/32 +f 744/543/32 752/545/32 746/551/32 +f 742/530/32 729/555/32 739/556/32 +f 729/555/32 738/553/32 739/556/32 +f 743/550/32 746/551/32 745/554/32 +f 752/545/32 694/557/32 746/551/32 +f 740/558/32 739/556/32 738/553/32 +f 745/554/32 740/558/32 738/553/32 +f 694/557/32 693/559/32 692/560/32 +f 694/557/32 692/560/32 746/551/32 +f 693/559/32 695/561/32 691/562/32 +f 692/560/32 693/559/32 691/562/32 +f 695/561/32 696/563/32 690/564/32 +f 691/562/32 695/561/32 690/564/32 +f 696/563/32 697/565/32 657/566/32 +f 690/564/32 696/563/32 689/567/32 +f 689/567/32 696/563/32 657/566/32 +f 698/568/32 705/569/32 709/570/32 +f 697/565/32 698/568/32 700/571/32 +f 657/566/32 697/565/32 700/571/32 +f 698/568/32 709/570/32 699/572/32 +f 698/568/32 699/572/32 700/571/32 +f 688/573/32 689/567/32 637/574/32 +f 646/575/32 657/566/32 658/576/32 +f 682/515/32 688/573/32 638/513/32 +f 657/566/32 646/575/32 637/574/32 +f 689/567/32 657/566/32 637/574/32 +f 656/577/32 659/578/32 647/579/32 +f 659/578/32 648/580/32 647/579/32 +f 658/576/32 656/577/32 646/575/32 +f 632/532/32 677/531/32 633/581/32 +f 677/531/32 678/582/32 633/581/32 +f 678/582/32 682/515/32 683/514/32 +f 656/577/32 647/579/32 646/575/32 +f 683/514/32 633/581/32 678/582/32 +f 688/573/32 637/574/32 638/513/32 +f 622/518/13 796/583/13 791/584/13 +f 792/585/13 793/586/13 622/518/13 +f 793/586/13 794/587/13 622/518/13 +f 622/518/13 791/584/13 792/585/13 +f 787/588/13 786/589/13 622/518/13 +f 790/517/13 789/590/13 622/518/13 +f 789/590/13 788/591/13 622/518/13 +f 788/591/13 787/588/13 622/518/13 +f 797/592/13 798/593/13 622/518/13 +f 798/593/13 783/594/13 622/518/13 +f 622/518/13 794/587/13 797/592/13 +f 783/594/13 782/516/13 622/518/13 +f 623/521/29 640/595/29 639/596/29 +f 642/597/29 643/598/29 623/521/29 +f 643/598/29 644/599/29 623/521/29 +f 623/521/29 639/596/29 642/597/29 +f 651/600/29 649/601/29 623/521/29 +f 654/520/29 653/602/29 623/521/29 +f 653/602/29 652/603/29 623/521/29 +f 652/603/29 651/600/29 623/521/29 +f 645/604/29 648/605/29 623/521/29 +f 648/605/29 659/606/29 623/521/29 +f 623/521/29 644/599/29 645/604/29 +f 659/606/29 655/519/29 623/521/29 +f 707/607/4 711/608/4 710/609/4 +f 713/610/4 715/522/4 702/524/4 +f 715/522/4 716/611/4 704/523/4 +f 703/612/4 714/613/4 705/614/4 +f 707/607/4 710/609/4 706/615/4 +f 710/609/4 713/610/4 706/615/4 +f 702/524/4 701/616/4 713/610/4 +f 701/616/4 706/615/4 713/610/4 +f 714/613/4 703/612/4 716/611/4 +f 714/613/4 709/617/4 705/614/4 +f 703/612/4 704/523/4 716/611/4 +f 758/618/4 768/619/4 769/620/4 +f 772/621/4 766/622/4 760/623/4 +f 766/622/4 765/624/4 761/625/4 +f 772/621/4 760/623/4 759/626/4 +f 758/618/4 769/620/4 759/626/4 +f 769/620/4 772/621/4 759/626/4 +f 761/625/4 760/623/4 766/622/4 +f 765/624/4 770/525/4 763/527/4 +f 770/525/4 771/627/4 764/526/4 +f 763/527/4 762/628/4 765/624/4 +f 762/628/4 761/625/4 765/624/4 +f 731/629/3 736/630/3 737/631/3 +f 737/631/3 726/632/3 733/633/3 +f 726/632/3 724/634/3 733/633/3 +f 730/635/3 731/629/3 737/631/3 +f 735/636/3 734/637/3 724/634/3 +f 734/637/3 733/633/3 724/634/3 +f 733/633/3 730/635/3 737/631/3 +f 724/634/3 725/638/3 735/636/3 +f 725/638/3 727/528/3 735/636/3 +f 742/530/3 741/639/3 727/528/3 +f 741/639/3 735/636/3 727/528/3 +f 685/640/3 681/641/3 680/642/3 +f 679/643/3 674/644/3 686/645/3 +f 674/644/3 675/646/3 687/647/3 +f 679/643/3 684/648/3 680/642/3 +f 685/640/3 680/642/3 684/648/3 +f 686/645/3 684/648/3 679/643/3 +f 631/533/3 634/649/3 676/650/3 +f 634/649/3 687/647/3 675/646/3 +f 687/647/3 686/645/3 674/644/3 +f 675/646/3 676/650/3 634/649/3 +f 676/650/3 677/531/3 631/533/3 +usemtl BlackSurface +f 813/15/124 817/651/124 812/652/124 +f 815/3/125 820/653/125 814/654/125 +f 823/23/126 831/655/126 822/656/126 +f 828/6/127 826/657/127 829/658/127 +f 813/15/128 816/14/128 817/651/128 +f 815/3/129 821/2/129 820/653/129 +f 823/23/130 830/17/130 831/655/130 +f 828/6/131 827/5/131 826/657/131 +s 1 +f 829/659/132 826/660/133 838/347/46 +f 806/661/5 818/662/5 852/663/5 +f 812/664/134 617/338/41 857/394/62 +f 873/665/135 616/354/50 615/666/136 +f 822/667/137 611/27/8 877/26/7 +f 892/668/138 616/354/50 897/361/53 +f 814/669/139 820/670/140 898/336/39 +f 893/671/5 821/672/5 807/673/5 +f 832/674/141 608/345/44 837/331/34 +f 853/675/142 608/345/44 607/676/143 +f 811/677/5 824/678/5 872/679/5 +f 817/680/144 815/681/145 814/669/146 +f 819/682/147 813/683/148 812/664/149 +f 825/684/150 823/685/151 822/667/152 +f 831/686/153 828/687/154 829/659/155 +f 837/331/34 834/688/156 832/674/141 +f 834/688/156 840/397/157 835/689/158 +f 835/689/158 841/395/159 836/690/160 +f 836/690/160 838/347/161 833/691/162 +f 857/394/62 854/692/163 852/663/164 +f 859/409/165 855/693/166 854/692/163 +f 860/406/167 856/694/168 855/693/166 +f 856/694/168 858/344/43 853/675/142 +f 877/26/7 874/695/169 872/679/170 +f 879/419/171 875/696/172 874/695/169 +f 880/416/173 876/697/174 875/696/172 +f 876/697/174 878/352/48 873/665/135 +f 897/361/53 894/698/175 892/668/138 +f 894/698/175 900/426/176 895/699/177 +f 895/699/177 901/424/178 896/700/179 +f 896/700/179 898/336/180 893/671/181 +f 833/691/5 827/701/5 809/702/5 +f 611/27/8 831/686/182 829/659/132 +f 826/660/13 833/691/13 838/347/13 +f 838/347/46 611/27/8 829/659/132 +f 607/676/5 614/703/5 806/661/5 +f 614/703/5 808/704/5 806/661/5 +f 856/694/5 853/675/5 806/661/5 +f 853/675/5 607/676/5 806/661/5 +f 854/692/5 855/693/5 806/661/5 +f 855/693/5 856/694/5 806/661/5 +f 818/662/13 819/682/13 852/663/13 +f 852/663/5 854/692/5 806/661/5 +f 852/663/13 819/682/13 812/664/13 +f 812/664/134 817/680/183 617/338/41 +f 857/394/62 852/663/164 812/664/134 +f 873/665/135 878/352/48 616/354/50 +f 872/679/13 825/684/13 822/667/13 +f 822/667/137 831/686/182 611/27/8 +f 877/26/7 872/679/170 822/667/137 +f 892/668/138 615/666/136 616/354/50 +f 617/338/41 817/680/183 814/669/139 +f 820/670/13 893/671/13 898/336/13 +f 898/336/39 617/338/41 814/669/139 +f 808/704/5 614/703/5 807/673/5 +f 614/703/5 615/666/5 807/673/5 +f 615/666/5 892/668/5 807/673/5 +f 892/668/5 894/698/5 807/673/5 +f 894/698/5 895/699/5 807/673/5 +f 895/699/5 896/700/5 807/673/5 +f 893/671/13 820/670/13 821/672/13 +f 896/700/5 893/671/5 807/673/5 +f 832/674/141 607/676/143 608/345/44 +f 853/675/142 858/344/43 608/345/44 +f 615/666/5 614/703/5 811/677/5 +f 614/703/5 810/705/5 811/677/5 +f 876/697/5 873/665/5 811/677/5 +f 873/665/5 615/666/5 811/677/5 +f 874/695/5 875/696/5 811/677/5 +f 875/696/5 876/697/5 811/677/5 +f 824/678/13 825/684/13 872/679/13 +f 872/679/5 874/695/5 811/677/5 +f 817/680/144 816/706/184 815/681/145 +f 819/682/147 818/707/185 813/683/148 +f 825/684/150 824/708/186 823/685/151 +f 831/686/153 830/709/187 828/687/154 +f 837/331/34 839/400/188 834/688/156 +f 834/688/156 839/400/188 840/397/157 +f 835/689/158 840/397/157 841/395/159 +f 836/690/160 841/395/159 838/347/161 +f 857/394/62 859/409/165 854/692/163 +f 859/409/165 860/406/167 855/693/166 +f 860/406/167 861/404/189 856/694/168 +f 856/694/168 861/404/189 858/344/43 +f 877/26/7 879/419/171 874/695/169 +f 879/419/171 880/416/173 875/696/172 +f 880/416/173 881/414/190 876/697/174 +f 876/697/174 881/414/190 878/352/48 +f 897/361/53 899/429/191 894/698/175 +f 894/698/175 899/429/191 900/426/176 +f 895/699/177 900/426/176 901/424/178 +f 896/700/179 901/424/178 898/336/180 +f 810/705/5 614/703/5 809/702/5 +f 614/703/5 607/676/5 809/702/5 +f 607/676/5 832/674/5 809/702/5 +f 832/674/5 834/688/5 809/702/5 +f 834/688/5 835/689/5 809/702/5 +f 835/689/5 836/690/5 809/702/5 +f 833/691/13 826/660/13 827/701/13 +f 836/690/5 833/691/5 809/702/5 +usemtl Holes +f 72/710/32 76/711/32 73/712/32 +f 76/711/32 74/713/32 73/712/32 +f 78/714/32 76/711/32 75/715/32 +f 76/711/32 80/716/32 77/717/32 +f 6/718/32 72/710/32 23/719/32 +f 23/719/32 73/712/32 22/720/32 +f 73/712/32 21/721/32 22/720/32 +f 74/713/32 8/722/32 21/721/32 +f 77/717/32 29/723/32 74/713/32 +f 77/717/32 27/724/32 28/725/32 +f 80/716/32 7/726/32 27/724/32 +f 79/727/32 34/728/32 80/716/32 +f 32/729/32 79/727/32 78/714/32 +f 5/730/32 78/714/32 14/731/32 +f 14/731/32 75/715/32 13/732/32 +f 12/733/32 75/715/32 72/710/32 +f 83/734/29 82/735/30 81/736/30 +f 84/737/29 753/738/30 82/735/30 +f 83/734/29 86/739/18 84/737/29 +f 87/740/19 763/741/60 764/742/60 +f 7/726/22 81/736/30 31/743/22 +f 31/743/22 82/735/30 30/744/22 +f 30/744/22 753/738/30 751/745/22 +f 37/746/11 44/84/18 87/740/19 +f 36/747/11 87/740/19 86/739/18 +f 35/748/11 86/739/18 85/749/18 +f 5/750/11 85/749/18 32/751/18 +f 33/752/29 85/749/18 83/734/29 +f 33/752/29 81/736/30 34/753/30 +f 90/754/3 89/755/20 88/756/20 +f 91/757/3 784/758/20 89/755/20 +f 90/754/3 93/759/21 91/757/3 +f 93/759/21 749/760/3 91/757/3 +f 8/722/16 88/756/20 26/761/16 +f 26/761/16 89/755/20 25/762/16 +f 798/763/17 797/764/17 24/765/16 +f 24/765/16 794/72/17 11/69/16 +f 30/744/22 750/766/21 93/759/21 +f 31/743/22 93/759/21 92/767/21 +f 7/726/22 92/767/21 27/724/21 +f 28/725/3 92/767/21 90/754/3 +f 28/725/3 88/756/20 29/723/20 +f 97/768/13 95/769/14 94/770/14 +f 98/771/13 96/772/14 95/769/14 +f 97/768/13 101/773/15 98/771/13 +f 101/773/15 99/774/13 98/771/13 +f 6/775/12 94/770/14 20/776/12 +f 20/776/12 95/769/14 19/777/12 +f 95/769/14 18/778/12 19/777/12 +f 96/772/14 10/49/12 18/778/12 +f 99/774/13 45/60/14 96/772/14 +f 102/779/15 46/71/13 99/774/13 +f 24/765/16 47/70/15 102/779/15 +f 25/762/16 102/779/15 101/773/15 +f 26/761/16 101/773/15 100/780/15 +f 8/722/16 100/780/15 21/781/15 +f 22/782/13 100/780/15 97/768/13 +f 22/782/13 94/770/14 23/783/14 +f 106/784/4 104/785/9 103/786/9 +f 107/787/4 105/788/9 104/785/9 +f 106/784/4 110/789/10 107/787/4 +f 110/789/10 108/790/4 107/787/4 +f 5/791/11 103/786/9 35/792/11 +f 35/792/11 104/785/9 36/793/11 +f 104/785/9 37/794/11 36/793/11 +f 105/788/9 9/38/11 37/794/11 +f 108/790/4 48/36/9 105/788/9 +f 111/795/10 49/51/4 108/790/4 +f 18/778/12 50/50/10 111/795/10 +f 19/777/12 111/795/10 110/789/10 +f 20/776/12 110/789/10 109/796/10 +f 6/775/12 109/796/10 12/797/10 +f 13/798/4 109/796/10 106/784/4 +f 13/798/4 103/786/9 14/799/9 +f 175/800/32 179/801/32 176/802/32 +f 179/801/32 177/803/32 176/802/32 +f 181/804/32 179/801/32 178/805/32 +f 179/801/32 183/806/32 180/807/32 +f 113/808/32 175/800/32 127/809/32 +f 127/809/32 176/802/32 126/810/32 +f 176/802/32 125/811/32 126/810/32 +f 177/803/32 115/812/32 125/811/32 +f 180/807/32 133/813/32 177/803/32 +f 180/807/32 131/814/32 132/815/32 +f 183/806/32 114/816/32 131/814/32 +f 182/817/32 139/818/32 183/806/32 +f 137/819/32 182/817/32 181/804/32 +f 112/820/32 181/804/32 121/821/32 +f 121/821/32 178/805/32 120/822/32 +f 119/823/32 178/805/32 175/800/32 +f 186/824/29 185/825/30 184/826/30 +f 187/827/29 729/828/192 185/825/30 +f 186/824/29 189/829/18 187/827/29 +f 189/829/18 738/830/29 187/827/29 +f 114/816/22 184/826/30 136/831/22 +f 136/831/22 185/825/30 135/832/22 +f 728/833/193 727/834/23 134/835/22 +f 727/834/23 118/126/22 134/835/22 +f 141/836/11 743/837/18 189/829/18 +f 140/838/11 189/829/18 188/839/18 +f 112/840/11 188/839/18 137/841/18 +f 138/842/29 188/839/18 186/824/29 +f 138/842/29 184/826/30 139/843/30 +f 193/844/3 191/845/20 190/846/20 +f 194/847/3 192/848/20 191/845/20 +f 193/844/3 197/849/21 194/847/3 +f 197/849/21 195/850/3 194/847/3 +f 115/812/16 190/846/20 130/851/16 +f 130/851/16 191/845/20 129/852/16 +f 191/845/20 128/853/16 129/852/16 +f 192/848/20 117/106/16 128/853/16 +f 195/850/3 151/117/20 192/848/20 +f 198/854/21 152/128/3 195/850/3 +f 134/835/22 153/127/21 198/854/21 +f 135/832/22 198/854/21 197/849/21 +f 136/831/22 197/849/21 196/855/21 +f 114/816/22 196/855/21 131/814/21 +f 132/815/3 196/855/21 193/844/3 +f 132/815/3 190/846/20 133/813/20 +f 202/856/13 200/857/14 199/858/14 +f 203/859/13 201/860/14 200/857/14 +f 202/856/13 206/861/15 203/859/13 +f 206/861/15 204/862/13 203/859/13 +f 113/863/12 199/858/14 124/864/12 +f 124/864/12 200/857/14 123/865/12 +f 200/857/14 122/866/12 123/865/12 +f 201/860/14 116/95/12 122/866/12 +f 204/862/13 154/93/14 201/860/14 +f 207/867/15 155/108/13 204/862/13 +f 128/853/16 156/107/15 207/867/15 +f 129/852/16 207/867/15 206/861/15 +f 130/851/16 206/861/15 205/868/15 +f 115/812/16 205/868/15 125/869/15 +f 126/870/13 205/868/15 202/856/13 +f 126/870/13 199/858/14 127/871/14 +f 210/872/4 209/873/9 208/874/9 +f 211/875/4 747/876/9 209/873/9 +f 210/872/4 213/877/10 211/875/4 +f 213/877/10 748/878/4 211/875/4 +f 112/879/11 208/874/9 140/880/11 +f 140/880/11 209/873/9 141/881/11 +f 209/873/9 744/882/11 141/881/11 +f 122/866/12 782/883/58 783/884/58 +f 124/864/12 213/877/10 212/885/10 +f 113/863/12 212/885/10 119/886/10 +f 120/887/4 212/885/10 210/872/4 +f 120/887/4 208/874/9 121/888/9 +f 268/889/32 272/890/32 269/891/32 +f 272/890/32 270/892/32 269/891/32 +f 274/893/32 272/890/32 271/894/32 +f 272/890/32 276/895/32 273/896/32 +f 215/897/32 268/889/32 231/898/32 +f 231/898/32 269/891/32 230/899/32 +f 269/891/32 229/900/32 230/899/32 +f 270/892/32 217/901/32 229/900/32 +f 273/896/32 236/902/32 270/892/32 +f 273/896/32 234/903/32 235/904/32 +f 276/895/32 216/905/32 234/903/32 +f 275/906/32 241/907/32 276/895/32 +f 239/908/32 275/906/32 274/893/32 +f 214/909/32 274/893/32 222/910/32 +f 222/910/32 271/894/32 221/911/32 +f 220/912/32 271/894/32 268/889/32 +f 279/913/29 278/914/30 277/915/30 +f 280/916/29 697/917/30 278/914/30 +f 279/913/29 282/918/18 280/916/29 +f 283/919/18 703/920/60 705/921/60 +f 216/905/22 277/915/30 238/922/22 +f 238/922/22 278/914/30 237/923/22 +f 278/914/30 696/924/22 237/923/22 +f 244/925/11 248/175/18 283/919/18 +f 243/926/11 283/919/18 282/918/18 +f 242/927/11 282/918/18 281/928/18 +f 214/929/11 281/928/18 239/930/18 +f 240/931/29 281/928/18 279/913/29 +f 240/931/29 277/915/30 241/932/30 +f 286/933/3 285/934/20 284/935/20 +f 287/936/3 694/937/20 285/934/20 +f 286/933/3 289/938/21 287/936/3 +f 289/938/21 693/939/3 287/936/3 +f 217/901/16 284/935/20 233/940/16 +f 233/940/16 285/934/20 232/941/16 +f 285/934/20 752/942/16 232/941/16 +f 237/923/22 695/943/21 289/938/21 +f 238/922/22 289/938/21 288/944/21 +f 216/905/22 288/944/21 234/903/21 +f 235/904/3 288/944/21 286/933/3 +f 235/904/3 284/935/20 236/902/20 +f 293/945/13 291/946/14 290/947/14 +f 291/946/14 771/948/25 292/949/14 +f 293/945/13 296/950/15 294/951/13 +f 296/950/15 755/952/13 294/951/13 +f 215/953/12 290/947/14 228/954/12 +f 228/954/12 291/946/14 227/955/12 +f 291/946/14 226/956/12 227/955/12 +f 292/949/14 219/155/12 226/956/12 +f 770/957/25 249/162/14 292/949/14 +f 232/941/16 756/958/15 296/950/15 +f 233/940/16 296/950/15 295/959/15 +f 217/901/16 295/959/15 229/960/15 +f 230/961/13 295/959/15 293/945/13 +f 230/961/13 290/947/14 231/962/14 +f 300/963/4 298/964/9 297/965/9 +f 301/966/4 299/967/9 298/964/9 +f 300/963/4 304/968/10 301/966/4 +f 304/968/10 302/969/4 301/966/4 +f 214/970/11 297/965/9 242/971/11 +f 242/971/11 298/964/9 243/972/11 +f 298/964/9 244/973/11 243/972/11 +f 299/967/9 218/144/11 244/973/11 +f 302/969/4 250/142/9 299/967/9 +f 305/974/10 251/157/4 302/969/4 +f 226/956/12 252/156/10 305/974/10 +f 227/955/12 305/974/10 304/968/10 +f 228/954/12 304/968/10 303/975/10 +f 215/953/12 303/975/10 220/976/10 +f 221/977/4 303/975/10 300/963/4 +f 221/977/4 297/965/9 222/978/9 +f 352/979/32 356/980/32 353/981/32 +f 356/980/32 354/982/32 353/981/32 +f 358/983/32 356/980/32 355/984/32 +f 356/980/32 360/985/32 357/986/32 +f 307/987/32 352/979/32 319/988/32 +f 319/988/32 353/981/32 318/989/32 +f 353/981/32 317/990/32 318/989/32 +f 354/982/32 309/991/32 317/990/32 +f 357/986/32 325/992/32 354/982/32 +f 357/986/32 323/993/32 324/994/32 +f 360/985/32 308/995/32 323/993/32 +f 359/996/32 331/997/32 360/985/32 +f 329/998/32 359/996/32 358/983/32 +f 306/999/32 358/983/32 314/1000/32 +f 314/1000/32 355/984/32 313/1001/32 +f 312/1002/32 355/984/32 352/979/32 +f 363/1003/29 362/1004/30 361/1005/30 +f 364/1006/29 678/1007/194 362/1004/30 +f 363/1003/29 366/1008/18 364/1006/29 +f 366/1008/18 682/1009/29 364/1006/29 +f 308/995/22 361/1005/30 328/1010/22 +f 328/1010/22 362/1004/30 327/1011/22 +f 677/1012/195 676/1013/23 326/1014/22 +f 676/1013/23 311/197/22 326/1014/22 +f 333/1015/11 688/1016/18 366/1008/18 +f 332/1017/11 366/1008/18 365/1018/18 +f 306/1019/11 365/1018/18 329/1020/18 +f 330/1021/29 365/1018/18 363/1003/29 +f 330/1021/29 361/1005/30 331/1022/30 +f 370/1023/3 368/1024/20 367/1025/20 +f 371/1026/3 369/1027/20 368/1024/20 +f 370/1023/3 374/1028/21 371/1026/3 +f 374/1028/21 372/1029/3 371/1026/3 +f 309/991/16 367/1025/20 322/1030/16 +f 322/1030/16 368/1024/20 321/1031/16 +f 368/1024/20 320/1032/16 321/1031/16 +f 369/1027/20 310/186/16 320/1032/16 +f 372/1029/3 340/184/20 369/1027/20 +f 375/1033/21 341/199/3 372/1029/3 +f 326/1014/22 342/198/21 375/1033/21 +f 327/1011/22 375/1033/21 374/1028/21 +f 328/1010/22 374/1028/21 373/1034/21 +f 308/995/22 373/1034/21 323/993/21 +f 324/994/3 373/1034/21 370/1023/3 +f 324/994/3 367/1025/20 325/992/20 +f 378/1035/13 377/1036/14 376/1037/14 +f 379/1038/13 745/1039/14 377/1036/14 +f 378/1035/13 381/1040/15 379/1038/13 +f 381/1040/15 740/1041/13 379/1038/13 +f 307/1042/12 376/1037/14 316/1043/12 +f 316/1043/12 377/1036/14 315/1044/12 +f 377/1036/14 746/1045/12 315/1044/12 +f 320/1032/16 741/1046/57 742/1047/196 +f 322/1030/16 381/1040/15 380/1048/15 +f 309/991/16 380/1048/15 317/1049/15 +f 318/1050/13 380/1048/15 378/1035/13 +f 318/1050/13 376/1037/14 319/1051/14 +f 384/1052/4 383/1053/9 382/1054/9 +f 385/1055/4 690/1056/9 383/1053/9 +f 384/1052/4 387/1057/10 385/1055/4 +f 387/1057/10 691/1058/4 385/1055/4 +f 306/1059/11 382/1054/9 332/1060/11 +f 332/1060/11 383/1053/9 333/1061/11 +f 383/1053/9 689/1062/11 333/1061/11 +f 315/1044/12 692/1063/10 387/1057/10 +f 316/1043/12 387/1057/10 386/1064/10 +f 307/1042/12 386/1064/10 312/1065/10 +f 313/1066/4 386/1064/10 384/1052/4 +f 313/1066/4 382/1054/9 314/1067/9 +f 459/1068/32 463/1069/32 460/1070/32 +f 463/1069/32 461/1071/32 460/1070/32 +f 465/1072/32 463/1069/32 462/1073/32 +f 463/1069/32 467/1074/32 464/1075/32 +f 389/1076/32 459/1068/32 406/1077/32 +f 406/1077/32 460/1070/32 405/1078/32 +f 460/1070/32 404/1079/32 405/1078/32 +f 461/1071/32 391/1080/32 404/1079/32 +f 464/1075/32 411/1081/32 461/1071/32 +f 464/1075/32 409/1082/32 410/1083/32 +f 467/1074/32 390/1084/32 409/1082/32 +f 466/1085/32 417/1086/32 467/1074/32 +f 415/1087/32 466/1085/32 465/1072/32 +f 388/1088/32 465/1072/32 397/1089/32 +f 397/1089/32 462/1073/32 396/1090/32 +f 395/1091/32 462/1073/32 459/1068/32 +f 471/1092/29 469/1093/30 468/1094/30 +f 472/1095/29 470/1096/30 469/1093/30 +f 471/1092/29 475/1097/18 472/1095/29 +f 475/1097/18 473/1098/29 472/1095/29 +f 390/1084/22 468/1094/30 414/1099/22 +f 414/1099/22 469/1093/30 413/1100/22 +f 469/1093/30 412/1101/22 413/1100/22 +f 470/1096/30 394/246/22 412/1101/22 +f 473/1098/29 427/256/30 470/1096/30 +f 476/1102/18 428/267/29 473/1098/29 +f 420/1103/11 429/266/18 476/1102/18 +f 419/1104/11 476/1102/18 475/1097/18 +f 418/1105/11 475/1097/18 474/1106/18 +f 388/1107/11 474/1106/18 415/1108/18 +f 416/1109/29 474/1106/18 471/1092/29 +f 416/1109/29 468/1094/30 417/1110/30 +f 479/1111/3 478/1112/20 477/1113/20 +f 480/1114/3 658/1115/20 478/1112/20 +f 479/1111/3 482/1116/21 480/1114/3 +f 483/1117/21 655/1118/61 659/1119/61 +f 391/1080/16 477/1113/20 408/1120/16 +f 408/1120/16 478/1112/20 407/1121/16 +f 478/1112/20 657/1122/16 407/1121/16 +f 412/1101/22 430/247/21 483/1117/21 +f 413/1100/22 483/1117/21 482/1116/21 +f 414/1099/22 482/1116/21 481/1123/21 +f 390/1084/22 481/1123/21 409/1082/21 +f 410/1083/3 481/1123/21 479/1111/3 +f 410/1083/3 477/1113/20 411/1081/20 +f 487/1124/13 485/1125/14 484/1126/14 +f 485/1125/14 709/1127/25 486/1128/14 +f 487/1124/13 490/1129/15 488/1130/13 +f 490/1129/15 699/1131/13 488/1130/13 +f 389/1132/12 484/1126/14 403/1133/12 +f 403/1133/12 485/1125/14 402/1134/12 +f 485/1125/14 401/1135/12 402/1134/12 +f 486/1128/14 393/226/12 401/1135/12 +f 714/1136/28 431/234/27 486/1128/14 +f 407/1121/16 700/1137/15 490/1129/15 +f 408/1120/16 490/1129/15 489/1138/15 +f 391/1080/16 489/1138/15 404/1139/15 +f 405/1140/13 489/1138/15 487/1124/13 +f 405/1140/13 484/1126/14 406/1141/14 +f 494/1142/4 492/1143/9 491/1144/9 +f 495/1145/4 493/1146/9 492/1143/9 +f 494/1142/4 498/1147/10 495/1145/4 +f 498/1147/10 496/1148/4 495/1145/4 +f 388/1149/11 491/1144/9 418/1150/11 +f 418/1150/11 492/1143/9 419/1151/11 +f 492/1143/9 420/1152/11 419/1151/11 +f 493/1146/9 392/215/11 420/1152/11 +f 496/1148/4 432/213/9 493/1146/9 +f 499/1153/10 433/228/4 496/1148/4 +f 401/1135/12 434/227/10 499/1153/10 +f 402/1134/12 499/1153/10 498/1147/10 +f 403/1133/12 498/1147/10 497/1154/10 +f 389/1132/12 497/1154/10 395/1155/10 +f 396/1156/4 497/1154/10 494/1142/4 +f 396/1156/4 491/1144/9 397/1157/9 +f 567/1158/32 571/1159/32 568/1160/32 +f 571/1159/32 569/1161/32 568/1160/32 +f 573/1162/32 571/1159/32 570/1163/32 +f 571/1159/32 575/1164/32 572/1165/32 +f 501/1166/32 567/1158/32 517/1167/32 +f 517/1167/32 568/1160/32 516/1168/32 +f 568/1160/32 515/1169/32 516/1168/32 +f 569/1161/32 503/1170/32 515/1169/32 +f 572/1165/32 523/1171/32 569/1161/32 +f 572/1165/32 521/1172/32 522/1173/32 +f 575/1164/32 502/1174/32 521/1172/32 +f 574/1175/32 529/1176/32 575/1164/32 +f 527/1177/32 574/1175/32 573/1162/32 +f 500/1178/32 573/1162/32 509/1179/32 +f 509/1179/32 570/1163/32 508/1180/32 +f 507/1181/32 570/1163/32 567/1158/32 +f 579/1182/29 577/1183/30 576/1184/30 +f 580/1185/29 578/1186/30 577/1183/30 +f 579/1182/29 583/1187/18 580/1185/29 +f 583/1187/18 581/1188/29 580/1185/29 +f 502/1174/22 576/1184/30 526/1189/22 +f 526/1189/22 577/1183/30 525/1190/22 +f 577/1183/30 524/1191/22 525/1190/22 +f 578/1186/30 506/303/22 524/1191/22 +f 581/1188/29 539/314/30 578/1186/30 +f 584/1192/18 540/325/29 581/1188/29 +f 532/1193/11 541/324/18 584/1192/18 +f 531/1194/11 584/1192/18 583/1187/18 +f 530/1195/11 583/1187/18 582/1196/18 +f 500/1197/11 582/1196/18 527/1198/18 +f 528/1199/29 582/1196/18 579/1182/29 +f 528/1199/29 576/1184/30 529/1200/30 +f 588/1201/3 586/1202/20 585/1203/20 +f 589/1204/3 587/1205/20 586/1202/20 +f 588/1201/3 592/1206/21 589/1204/3 +f 592/1206/21 590/1207/3 589/1204/3 +f 503/1170/16 585/1203/20 520/1208/16 +f 520/1208/16 586/1202/20 519/1209/16 +f 586/1202/20 518/1210/16 519/1209/16 +f 587/1205/20 505/292/16 518/1210/16 +f 590/1207/3 542/290/20 587/1205/20 +f 593/1211/21 543/305/3 590/1207/3 +f 524/1191/22 544/304/21 593/1211/21 +f 525/1190/22 593/1211/21 592/1206/21 +f 526/1189/22 592/1206/21 591/1212/21 +f 502/1174/22 591/1212/21 521/1172/21 +f 522/1173/3 591/1212/21 588/1201/3 +f 522/1173/3 585/1203/20 523/1171/20 +f 596/1213/13 595/1214/14 594/1215/14 +f 597/1216/13 638/1217/14 595/1214/14 +f 596/1213/13 599/1218/15 597/1216/13 +f 599/1218/15 683/1219/13 597/1216/13 +f 501/1220/12 594/1215/14 514/1221/12 +f 514/1221/12 595/1214/14 513/1222/12 +f 595/1214/14 637/1223/12 513/1222/12 +f 518/1210/16 631/1224/57 632/1225/197 +f 520/1208/16 599/1218/15 598/1226/15 +f 503/1170/16 598/1226/15 515/1227/15 +f 516/1228/13 598/1226/15 596/1213/13 +f 516/1228/13 594/1215/14 517/1229/14 +f 603/1230/4 601/1231/9 600/1232/9 +f 601/1231/9 648/1233/31 602/1234/9 +f 603/1230/4 606/1235/10 604/1236/4 +f 606/1235/10 647/1237/4 604/1236/4 +f 500/1238/11 600/1232/9 530/1239/11 +f 530/1239/11 601/1231/9 531/1240/11 +f 601/1231/9 532/1241/11 531/1240/11 +f 602/1234/9 504/275/11 532/1241/11 +f 645/1242/31 545/273/9 602/1234/9 +f 513/1222/12 646/1243/10 606/1235/10 +f 514/1221/12 606/1235/10 605/1244/10 +f 501/1220/12 605/1244/10 507/1245/10 +f 508/1246/4 605/1244/10 603/1230/4 +f 508/1246/4 600/1232/9 509/1247/9 +f 483/1117/21 654/392/61 655/1118/61 +f 518/1210/16 634/379/57 631/1224/57 +f 122/866/12 790/367/58 782/883/58 +f 87/740/19 762/389/59 763/741/60 +f 283/919/18 704/390/60 703/920/60 +f 320/1032/16 735/391/57 741/1046/57 +f 72/710/32 75/715/32 76/711/32 +f 76/711/32 77/717/32 74/713/32 +f 78/714/32 79/727/32 76/711/32 +f 76/711/32 79/727/32 80/716/32 +f 6/718/32 12/733/32 72/710/32 +f 23/719/32 72/710/32 73/712/32 +f 73/712/32 74/713/32 21/721/32 +f 74/713/32 29/723/32 8/722/32 +f 77/717/32 28/725/32 29/723/32 +f 77/717/32 80/716/32 27/724/32 +f 80/716/32 34/728/32 7/726/32 +f 79/727/32 33/1248/32 34/728/32 +f 32/729/32 33/1248/32 79/727/32 +f 5/730/32 32/729/32 78/714/32 +f 14/731/32 78/714/32 75/715/32 +f 12/733/32 13/732/32 75/715/32 +f 83/734/29 84/737/29 82/735/30 +f 84/737/29 754/1249/29 753/738/30 +f 83/734/29 85/749/18 86/739/18 +f 754/1249/29 84/737/29 764/742/60 +f 84/737/29 86/739/18 764/742/60 +f 86/739/18 87/740/19 764/742/60 +f 7/726/22 34/753/30 81/736/30 +f 31/743/22 81/736/30 82/735/30 +f 30/744/22 82/735/30 753/738/30 +f 37/746/11 9/83/11 44/84/18 +f 36/747/11 37/746/11 87/740/19 +f 35/748/11 36/747/11 86/739/18 +f 5/750/11 35/748/11 85/749/18 +f 33/752/29 32/751/18 85/749/18 +f 33/752/29 83/734/29 81/736/30 +f 90/754/3 91/757/3 89/755/20 +f 91/757/3 749/760/3 784/758/20 +f 90/754/3 92/767/21 93/759/21 +f 93/759/21 750/766/21 749/760/3 +f 8/722/16 29/723/20 88/756/20 +f 26/761/16 88/756/20 89/755/20 +f 24/765/16 25/762/16 798/763/17 +f 25/762/16 89/755/20 798/763/17 +f 89/755/20 784/758/20 798/763/17 +f 24/765/16 797/764/17 794/72/17 +f 30/744/22 751/745/22 750/766/21 +f 31/743/22 30/744/22 93/759/21 +f 7/726/22 31/743/22 92/767/21 +f 28/725/3 27/724/21 92/767/21 +f 28/725/3 90/754/3 88/756/20 +f 97/768/13 98/771/13 95/769/14 +f 98/771/13 99/774/13 96/772/14 +f 97/768/13 100/780/15 101/773/15 +f 101/773/15 102/779/15 99/774/13 +f 6/775/12 23/783/14 94/770/14 +f 20/776/12 94/770/14 95/769/14 +f 95/769/14 96/772/14 18/778/12 +f 96/772/14 45/60/14 10/49/12 +f 99/774/13 46/71/13 45/60/14 +f 102/779/15 47/70/15 46/71/13 +f 24/765/16 11/69/16 47/70/15 +f 25/762/16 24/765/16 102/779/15 +f 26/761/16 25/762/16 101/773/15 +f 8/722/16 26/761/16 100/780/15 +f 22/782/13 21/781/15 100/780/15 +f 22/782/13 97/768/13 94/770/14 +f 106/784/4 107/787/4 104/785/9 +f 107/787/4 108/790/4 105/788/9 +f 106/784/4 109/796/10 110/789/10 +f 110/789/10 111/795/10 108/790/4 +f 5/791/11 14/799/9 103/786/9 +f 35/792/11 103/786/9 104/785/9 +f 104/785/9 105/788/9 37/794/11 +f 105/788/9 48/36/9 9/38/11 +f 108/790/4 49/51/4 48/36/9 +f 111/795/10 50/50/10 49/51/4 +f 18/778/12 10/49/12 50/50/10 +f 19/777/12 18/778/12 111/795/10 +f 20/776/12 19/777/12 110/789/10 +f 6/775/12 20/776/12 109/796/10 +f 13/798/4 12/797/10 109/796/10 +f 13/798/4 106/784/4 103/786/9 +f 175/800/32 178/805/32 179/801/32 +f 179/801/32 180/807/32 177/803/32 +f 181/804/32 182/817/32 179/801/32 +f 179/801/32 182/817/32 183/806/32 +f 113/808/32 119/823/32 175/800/32 +f 127/809/32 175/800/32 176/802/32 +f 176/802/32 177/803/32 125/811/32 +f 177/803/32 133/813/32 115/812/32 +f 180/807/32 132/815/32 133/813/32 +f 180/807/32 183/806/32 131/814/32 +f 183/806/32 139/818/32 114/816/32 +f 182/817/32 138/1250/32 139/818/32 +f 137/819/32 138/1250/32 182/817/32 +f 112/820/32 137/819/32 181/804/32 +f 121/821/32 181/804/32 178/805/32 +f 119/823/32 120/822/32 178/805/32 +f 186/824/29 187/827/29 185/825/30 +f 187/827/29 738/830/29 729/828/192 +f 186/824/29 188/839/18 189/829/18 +f 189/829/18 743/837/18 738/830/29 +f 114/816/22 139/843/30 184/826/30 +f 136/831/22 184/826/30 185/825/30 +f 134/835/22 135/832/22 728/833/193 +f 135/832/22 185/825/30 728/833/193 +f 185/825/30 729/828/192 728/833/193 +f 727/834/23 725/129/23 118/126/22 +f 141/836/11 744/1251/11 743/837/18 +f 140/838/11 141/836/11 189/829/18 +f 112/840/11 140/838/11 188/839/18 +f 138/842/29 137/841/18 188/839/18 +f 138/842/29 186/824/29 184/826/30 +f 193/844/3 194/847/3 191/845/20 +f 194/847/3 195/850/3 192/848/20 +f 193/844/3 196/855/21 197/849/21 +f 197/849/21 198/854/21 195/850/3 +f 115/812/16 133/813/20 190/846/20 +f 130/851/16 190/846/20 191/845/20 +f 191/845/20 192/848/20 128/853/16 +f 192/848/20 151/117/20 117/106/16 +f 195/850/3 152/128/3 151/117/20 +f 198/854/21 153/127/21 152/128/3 +f 134/835/22 118/126/22 153/127/21 +f 135/832/22 134/835/22 198/854/21 +f 136/831/22 135/832/22 197/849/21 +f 114/816/22 136/831/22 196/855/21 +f 132/815/3 131/814/21 196/855/21 +f 132/815/3 193/844/3 190/846/20 +f 202/856/13 203/859/13 200/857/14 +f 203/859/13 204/862/13 201/860/14 +f 202/856/13 205/868/15 206/861/15 +f 206/861/15 207/867/15 204/862/13 +f 113/863/12 127/871/14 199/858/14 +f 124/864/12 199/858/14 200/857/14 +f 200/857/14 201/860/14 122/866/12 +f 201/860/14 154/93/14 116/95/12 +f 204/862/13 155/108/13 154/93/14 +f 207/867/15 156/107/15 155/108/13 +f 128/853/16 117/106/16 156/107/15 +f 129/852/16 128/853/16 207/867/15 +f 130/851/16 129/852/16 206/861/15 +f 115/812/16 130/851/16 205/868/15 +f 126/870/13 125/869/15 205/868/15 +f 126/870/13 202/856/13 199/858/14 +f 210/872/4 211/875/4 209/873/9 +f 211/875/4 748/878/4 747/876/9 +f 210/872/4 212/885/10 213/877/10 +f 213/877/10 778/1252/198 748/878/4 +f 112/879/11 121/888/9 208/874/9 +f 140/880/11 208/874/9 209/873/9 +f 209/873/9 747/876/9 744/882/11 +f 778/1252/198 213/877/10 783/884/58 +f 213/877/10 123/865/12 783/884/58 +f 123/865/12 122/866/12 783/884/58 +f 124/864/12 123/865/12 213/877/10 +f 113/863/12 124/864/12 212/885/10 +f 120/887/4 119/886/10 212/885/10 +f 120/887/4 210/872/4 208/874/9 +f 268/889/32 271/894/32 272/890/32 +f 272/890/32 273/896/32 270/892/32 +f 274/893/32 275/906/32 272/890/32 +f 272/890/32 275/906/32 276/895/32 +f 215/897/32 220/912/32 268/889/32 +f 231/898/32 268/889/32 269/891/32 +f 269/891/32 270/892/32 229/900/32 +f 270/892/32 236/902/32 217/901/32 +f 273/896/32 235/904/32 236/902/32 +f 273/896/32 276/895/32 234/903/32 +f 276/895/32 241/907/32 216/905/32 +f 275/906/32 240/1253/32 241/907/32 +f 239/908/32 240/1253/32 275/906/32 +f 214/909/32 239/908/32 274/893/32 +f 222/910/32 274/893/32 271/894/32 +f 220/912/32 221/911/32 271/894/32 +f 279/913/29 280/916/29 278/914/30 +f 280/916/29 698/1254/29 697/917/30 +f 279/913/29 281/928/18 282/918/18 +f 698/1254/29 280/916/29 705/921/60 +f 280/916/29 282/918/18 705/921/60 +f 282/918/18 283/919/18 705/921/60 +f 216/905/22 241/932/30 277/915/30 +f 238/922/22 277/915/30 278/914/30 +f 278/914/30 697/917/30 696/924/22 +f 244/925/11 218/174/11 248/175/18 +f 243/926/11 244/925/11 283/919/18 +f 242/927/11 243/926/11 282/918/18 +f 214/929/11 242/927/11 281/928/18 +f 240/931/29 239/930/18 281/928/18 +f 240/931/29 279/913/29 277/915/30 +f 286/933/3 287/936/3 285/934/20 +f 287/936/3 693/939/3 694/937/20 +f 286/933/3 288/944/21 289/938/21 +f 289/938/21 695/943/21 693/939/3 +f 217/901/16 236/902/20 284/935/20 +f 233/940/16 284/935/20 285/934/20 +f 285/934/20 694/937/20 752/942/16 +f 237/923/22 696/924/22 695/943/21 +f 238/922/22 237/923/22 289/938/21 +f 216/905/22 238/922/22 288/944/21 +f 235/904/3 234/903/21 288/944/21 +f 235/904/3 286/933/3 284/935/20 +f 293/945/13 294/951/13 291/946/14 +f 291/946/14 294/951/13 771/948/25 +f 294/951/13 755/952/13 771/948/25 +f 771/948/25 770/957/25 292/949/14 +f 293/945/13 295/959/15 296/950/15 +f 296/950/15 756/958/15 755/952/13 +f 215/953/12 231/962/14 290/947/14 +f 228/954/12 290/947/14 291/946/14 +f 291/946/14 292/949/14 226/956/12 +f 292/949/14 249/162/14 219/155/12 +f 770/957/25 765/439/25 249/162/14 +f 232/941/16 752/942/16 756/958/15 +f 233/940/16 232/941/16 296/950/15 +f 217/901/16 233/940/16 295/959/15 +f 230/961/13 229/960/15 295/959/15 +f 230/961/13 293/945/13 290/947/14 +f 300/963/4 301/966/4 298/964/9 +f 301/966/4 302/969/4 299/967/9 +f 300/963/4 303/975/10 304/968/10 +f 304/968/10 305/974/10 302/969/4 +f 214/970/11 222/978/9 297/965/9 +f 242/971/11 297/965/9 298/964/9 +f 298/964/9 299/967/9 244/973/11 +f 299/967/9 250/142/9 218/144/11 +f 302/969/4 251/157/4 250/142/9 +f 305/974/10 252/156/10 251/157/4 +f 226/956/12 219/155/12 252/156/10 +f 227/955/12 226/956/12 305/974/10 +f 228/954/12 227/955/12 304/968/10 +f 215/953/12 228/954/12 303/975/10 +f 221/977/4 220/976/10 303/975/10 +f 221/977/4 300/963/4 297/965/9 +f 352/979/32 355/984/32 356/980/32 +f 356/980/32 357/986/32 354/982/32 +f 358/983/32 359/996/32 356/980/32 +f 356/980/32 359/996/32 360/985/32 +f 307/987/32 312/1002/32 352/979/32 +f 319/988/32 352/979/32 353/981/32 +f 353/981/32 354/982/32 317/990/32 +f 354/982/32 325/992/32 309/991/32 +f 357/986/32 324/994/32 325/992/32 +f 357/986/32 360/985/32 323/993/32 +f 360/985/32 331/997/32 308/995/32 +f 359/996/32 330/1255/32 331/997/32 +f 329/998/32 330/1255/32 359/996/32 +f 306/999/32 329/998/32 358/983/32 +f 314/1000/32 358/983/32 355/984/32 +f 312/1002/32 313/1001/32 355/984/32 +f 363/1003/29 364/1006/29 362/1004/30 +f 364/1006/29 682/1009/29 678/1007/194 +f 363/1003/29 365/1018/18 366/1008/18 +f 366/1008/18 688/1016/18 682/1009/29 +f 308/995/22 331/1022/30 361/1005/30 +f 328/1010/22 361/1005/30 362/1004/30 +f 326/1014/22 327/1011/22 677/1012/195 +f 327/1011/22 362/1004/30 677/1012/195 +f 362/1004/30 678/1007/194 677/1012/195 +f 676/1013/23 675/200/23 311/197/22 +f 333/1015/11 689/1256/11 688/1016/18 +f 332/1017/11 333/1015/11 366/1008/18 +f 306/1019/11 332/1017/11 365/1018/18 +f 330/1021/29 329/1020/18 365/1018/18 +f 330/1021/29 363/1003/29 361/1005/30 +f 370/1023/3 371/1026/3 368/1024/20 +f 371/1026/3 372/1029/3 369/1027/20 +f 370/1023/3 373/1034/21 374/1028/21 +f 374/1028/21 375/1033/21 372/1029/3 +f 309/991/16 325/992/20 367/1025/20 +f 322/1030/16 367/1025/20 368/1024/20 +f 368/1024/20 369/1027/20 320/1032/16 +f 369/1027/20 340/184/20 310/186/16 +f 372/1029/3 341/199/3 340/184/20 +f 375/1033/21 342/198/21 341/199/3 +f 326/1014/22 311/197/22 342/198/21 +f 327/1011/22 326/1014/22 375/1033/21 +f 328/1010/22 327/1011/22 374/1028/21 +f 308/995/22 328/1010/22 373/1034/21 +f 324/994/3 323/993/21 373/1034/21 +f 324/994/3 370/1023/3 367/1025/20 +f 378/1035/13 379/1038/13 377/1036/14 +f 379/1038/13 740/1041/13 745/1039/14 +f 378/1035/13 380/1048/15 381/1040/15 +f 381/1040/15 739/1257/199 740/1041/13 +f 307/1042/12 319/1051/14 376/1037/14 +f 316/1043/12 376/1037/14 377/1036/14 +f 377/1036/14 745/1039/14 746/1045/12 +f 739/1257/199 381/1040/15 742/1047/196 +f 381/1040/15 321/1031/16 742/1047/196 +f 321/1031/16 320/1032/16 742/1047/196 +f 322/1030/16 321/1031/16 381/1040/15 +f 309/991/16 322/1030/16 380/1048/15 +f 318/1050/13 317/1049/15 380/1048/15 +f 318/1050/13 378/1035/13 376/1037/14 +f 384/1052/4 385/1055/4 383/1053/9 +f 385/1055/4 691/1058/4 690/1056/9 +f 384/1052/4 386/1064/10 387/1057/10 +f 387/1057/10 692/1063/10 691/1058/4 +f 306/1059/11 314/1067/9 382/1054/9 +f 332/1060/11 382/1054/9 383/1053/9 +f 383/1053/9 690/1056/9 689/1062/11 +f 315/1044/12 746/1045/12 692/1063/10 +f 316/1043/12 315/1044/12 387/1057/10 +f 307/1042/12 316/1043/12 386/1064/10 +f 313/1066/4 312/1065/10 386/1064/10 +f 313/1066/4 384/1052/4 382/1054/9 +f 459/1068/32 462/1073/32 463/1069/32 +f 463/1069/32 464/1075/32 461/1071/32 +f 465/1072/32 466/1085/32 463/1069/32 +f 463/1069/32 466/1085/32 467/1074/32 +f 389/1076/32 395/1091/32 459/1068/32 +f 406/1077/32 459/1068/32 460/1070/32 +f 460/1070/32 461/1071/32 404/1079/32 +f 461/1071/32 411/1081/32 391/1080/32 +f 464/1075/32 410/1083/32 411/1081/32 +f 464/1075/32 467/1074/32 409/1082/32 +f 467/1074/32 417/1086/32 390/1084/32 +f 466/1085/32 416/1258/32 417/1086/32 +f 415/1087/32 416/1258/32 466/1085/32 +f 388/1088/32 415/1087/32 465/1072/32 +f 397/1089/32 465/1072/32 462/1073/32 +f 395/1091/32 396/1090/32 462/1073/32 +f 471/1092/29 472/1095/29 469/1093/30 +f 472/1095/29 473/1098/29 470/1096/30 +f 471/1092/29 474/1106/18 475/1097/18 +f 475/1097/18 476/1102/18 473/1098/29 +f 390/1084/22 417/1110/30 468/1094/30 +f 414/1099/22 468/1094/30 469/1093/30 +f 469/1093/30 470/1096/30 412/1101/22 +f 470/1096/30 427/256/30 394/246/22 +f 473/1098/29 428/267/29 427/256/30 +f 476/1102/18 429/266/18 428/267/29 +f 420/1103/11 392/265/11 429/266/18 +f 419/1104/11 420/1103/11 476/1102/18 +f 418/1105/11 419/1104/11 475/1097/18 +f 388/1107/11 418/1105/11 474/1106/18 +f 416/1109/29 415/1108/18 474/1106/18 +f 416/1109/29 471/1092/29 468/1094/30 +f 479/1111/3 480/1114/3 478/1112/20 +f 480/1114/3 656/1259/3 658/1115/20 +f 479/1111/3 481/1123/21 482/1116/21 +f 656/1259/3 480/1114/3 659/1119/61 +f 480/1114/3 482/1116/21 659/1119/61 +f 482/1116/21 483/1117/21 659/1119/61 +f 391/1080/16 411/1081/20 477/1113/20 +f 408/1120/16 477/1113/20 478/1112/20 +f 478/1112/20 658/1115/20 657/1122/16 +f 412/1101/22 394/246/22 430/247/21 +f 413/1100/22 412/1101/22 483/1117/21 +f 414/1099/22 413/1100/22 482/1116/21 +f 390/1084/22 414/1099/22 481/1123/21 +f 410/1083/3 409/1082/21 481/1123/21 +f 410/1083/3 479/1111/3 477/1113/20 +f 487/1124/13 488/1130/13 485/1125/14 +f 485/1125/14 488/1130/13 709/1127/25 +f 488/1130/13 699/1131/13 709/1127/25 +f 709/1127/25 714/1136/28 486/1128/14 +f 487/1124/13 489/1138/15 490/1129/15 +f 490/1129/15 700/1137/15 699/1131/13 +f 389/1132/12 406/1141/14 484/1126/14 +f 403/1133/12 484/1126/14 485/1125/14 +f 485/1125/14 486/1128/14 401/1135/12 +f 486/1128/14 431/234/27 393/226/12 +f 714/1136/28 716/238/25 431/234/27 +f 407/1121/16 657/1122/16 700/1137/15 +f 408/1120/16 407/1121/16 490/1129/15 +f 391/1080/16 408/1120/16 489/1138/15 +f 405/1140/13 404/1139/15 489/1138/15 +f 405/1140/13 487/1124/13 484/1126/14 +f 494/1142/4 495/1145/4 492/1143/9 +f 495/1145/4 496/1148/4 493/1146/9 +f 494/1142/4 497/1154/10 498/1147/10 +f 498/1147/10 499/1153/10 496/1148/4 +f 388/1149/11 397/1157/9 491/1144/9 +f 418/1150/11 491/1144/9 492/1143/9 +f 492/1143/9 493/1146/9 420/1152/11 +f 493/1146/9 432/213/9 392/215/11 +f 496/1148/4 433/228/4 432/213/9 +f 499/1153/10 434/227/10 433/228/4 +f 401/1135/12 393/226/12 434/227/10 +f 402/1134/12 401/1135/12 499/1153/10 +f 403/1133/12 402/1134/12 498/1147/10 +f 389/1132/12 403/1133/12 497/1154/10 +f 396/1156/4 395/1155/10 497/1154/10 +f 396/1156/4 494/1142/4 491/1144/9 +f 567/1158/32 570/1163/32 571/1159/32 +f 571/1159/32 572/1165/32 569/1161/32 +f 573/1162/32 574/1175/32 571/1159/32 +f 571/1159/32 574/1175/32 575/1164/32 +f 501/1166/32 507/1181/32 567/1158/32 +f 517/1167/32 567/1158/32 568/1160/32 +f 568/1160/32 569/1161/32 515/1169/32 +f 569/1161/32 523/1171/32 503/1170/32 +f 572/1165/32 522/1173/32 523/1171/32 +f 572/1165/32 575/1164/32 521/1172/32 +f 575/1164/32 529/1176/32 502/1174/32 +f 574/1175/32 528/1260/32 529/1176/32 +f 527/1177/32 528/1260/32 574/1175/32 +f 500/1178/32 527/1177/32 573/1162/32 +f 509/1179/32 573/1162/32 570/1163/32 +f 507/1181/32 508/1180/32 570/1163/32 +f 579/1182/29 580/1185/29 577/1183/30 +f 580/1185/29 581/1188/29 578/1186/30 +f 579/1182/29 582/1196/18 583/1187/18 +f 583/1187/18 584/1192/18 581/1188/29 +f 502/1174/22 529/1200/30 576/1184/30 +f 526/1189/22 576/1184/30 577/1183/30 +f 577/1183/30 578/1186/30 524/1191/22 +f 578/1186/30 539/314/30 506/303/22 +f 581/1188/29 540/325/29 539/314/30 +f 584/1192/18 541/324/18 540/325/29 +f 532/1193/11 504/323/11 541/324/18 +f 531/1194/11 532/1193/11 584/1192/18 +f 530/1195/11 531/1194/11 583/1187/18 +f 500/1197/11 530/1195/11 582/1196/18 +f 528/1199/29 527/1198/18 582/1196/18 +f 528/1199/29 579/1182/29 576/1184/30 +f 588/1201/3 589/1204/3 586/1202/20 +f 589/1204/3 590/1207/3 587/1205/20 +f 588/1201/3 591/1212/21 592/1206/21 +f 592/1206/21 593/1211/21 590/1207/3 +f 503/1170/16 523/1171/20 585/1203/20 +f 520/1208/16 585/1203/20 586/1202/20 +f 586/1202/20 587/1205/20 518/1210/16 +f 587/1205/20 542/290/20 505/292/16 +f 590/1207/3 543/305/3 542/290/20 +f 593/1211/21 544/304/21 543/305/3 +f 524/1191/22 506/303/22 544/304/21 +f 525/1190/22 524/1191/22 593/1211/21 +f 526/1189/22 525/1190/22 592/1206/21 +f 502/1174/22 526/1189/22 591/1212/21 +f 522/1173/3 521/1172/21 591/1212/21 +f 522/1173/3 588/1201/3 585/1203/20 +f 596/1213/13 597/1216/13 595/1214/14 +f 597/1216/13 683/1219/13 638/1217/14 +f 596/1213/13 598/1226/15 599/1218/15 +f 599/1218/15 633/1261/200 683/1219/13 +f 501/1220/12 517/1229/14 594/1215/14 +f 514/1221/12 594/1215/14 595/1214/14 +f 595/1214/14 638/1217/14 637/1223/12 +f 633/1261/200 599/1218/15 632/1225/197 +f 599/1218/15 519/1209/16 632/1225/197 +f 519/1209/16 518/1210/16 632/1225/197 +f 520/1208/16 519/1209/16 599/1218/15 +f 503/1170/16 520/1208/16 598/1226/15 +f 516/1228/13 515/1227/15 598/1226/15 +f 516/1228/13 596/1213/13 594/1215/14 +f 603/1230/4 604/1236/4 601/1231/9 +f 601/1231/9 604/1236/4 648/1233/31 +f 604/1236/4 647/1237/4 648/1233/31 +f 648/1233/31 645/1242/31 602/1234/9 +f 603/1230/4 605/1244/10 606/1235/10 +f 606/1235/10 646/1243/10 647/1237/4 +f 500/1238/11 509/1247/9 600/1232/9 +f 530/1239/11 600/1232/9 601/1231/9 +f 601/1231/9 602/1234/9 532/1241/11 +f 602/1234/9 545/273/9 504/275/11 +f 645/1242/31 644/281/31 545/273/9 +f 513/1222/12 637/1223/12 646/1243/10 +f 514/1221/12 513/1222/12 606/1235/10 +f 501/1220/12 514/1221/12 605/1244/10 +f 508/1246/4 507/1245/10 605/1244/10 +f 508/1246/4 603/1230/4 600/1232/9 +f 483/1117/21 430/247/21 654/392/61 +f 518/1210/16 505/292/16 634/379/57 +f 122/866/12 116/95/12 790/367/58 +f 87/740/19 44/84/18 762/389/59 +f 283/919/18 248/175/18 704/390/60 +f 320/1032/16 310/186/16 735/391/57 +usemtl Lamp +s off +f 929/1262/32 915/1263/32 942/1264/32 +f 938/1265/5 912/1266/5 927/1267/5 +f 938/1265/4 941/1268/4 942/1264/4 +f 914/1269/5 920/1270/5 912/1266/5 +f 913/1271/32 935/1272/32 915/1263/32 +f 930/1273/29 939/1274/29 926/1275/29 +f 932/1276/4 934/1277/4 933/1278/4 +f 926/1275/3 928/1279/3 927/1280/3 +f 947/1281/4 949/1282/4 948/1283/4 +f 936/1284/13 921/1285/13 932/1276/13 +f 919/1286/32 954/1287/32 965/1288/32 +f 916/1289/5 963/1290/5 950/1291/5 +f 965/1288/3 967/1292/3 966/1293/3 +f 945/1294/5 918/1295/5 916/1289/5 +f 960/1296/32 917/1297/32 919/1286/32 +f 962/1298/29 953/1299/29 951/1300/29 +f 957/1301/3 960/1296/3 956/1302/3 +f 951/1300/4 954/1303/4 950/1304/4 +f 944/1305/13 959/1306/13 957/1301/13 +f 927/1267/201 940/1307/201 938/1265/201 +f 928/1308/202 939/1274/202 940/1307/202 +f 942/1264/203 931/1309/203 929/1262/203 +f 943/1310/204 930/1273/204 931/1311/204 +f 933/1278/205 922/1312/205 920/1270/205 +f 934/1313/206 921/1285/206 922/1314/206 +f 924/1315/207 937/1316/207 935/1272/207 +f 925/1317/208 936/1284/208 937/1316/208 +f 951/1300/202 964/1318/202 962/1298/202 +f 952/1319/201 963/1290/201 964/1318/201 +f 966/1293/204 955/1320/204 953/1299/204 +f 967/1321/203 954/1287/203 955/1322/203 +f 957/1301/206 946/1323/206 944/1305/206 +f 958/1324/205 945/1294/205 946/1325/205 +f 948/1326/208 961/1327/208 959/1306/208 +f 949/1328/207 960/1296/207 961/1327/207 +f 920/1329/3 923/1330/3 924/1331/3 +f 929/1262/32 913/1271/32 915/1263/32 +f 938/1265/5 914/1269/5 912/1266/5 +f 914/1269/4 938/1265/4 942/1264/4 +f 938/1265/4 940/1332/4 939/1274/4 +f 941/1268/4 938/1265/4 939/1274/4 +f 941/1268/4 943/1333/4 942/1264/4 +f 942/1264/4 915/1263/4 914/1269/4 +f 914/1269/5 933/1278/5 920/1270/5 +f 913/1271/32 924/1315/32 935/1272/32 +f 930/1273/29 941/1268/29 939/1274/29 +f 933/1278/4 914/1269/4 915/1263/4 +f 915/1263/4 935/1272/4 933/1278/4 +f 935/1272/4 937/1334/4 936/1284/4 +f 933/1278/4 935/1272/4 932/1276/4 +f 936/1284/4 932/1276/4 935/1272/4 +f 927/1280/3 912/1335/3 913/1336/3 +f 913/1336/3 929/1337/3 927/1280/3 +f 929/1337/3 931/1338/3 930/1273/3 +f 927/1280/3 929/1337/3 926/1275/3 +f 930/1273/3 926/1275/3 929/1337/3 +f 948/1283/4 944/1339/4 945/1340/4 +f 944/1339/4 946/1341/4 945/1340/4 +f 945/1340/4 916/1342/4 947/1281/4 +f 948/1283/4 945/1340/4 947/1281/4 +f 916/1342/4 917/1343/4 947/1281/4 +f 936/1284/13 923/1344/13 921/1285/13 +f 919/1286/32 917/1297/32 954/1287/32 +f 916/1289/5 918/1295/5 963/1290/5 +f 966/1293/3 962/1298/3 963/1290/3 +f 962/1298/3 964/1345/3 963/1290/3 +f 963/1290/3 918/1295/3 965/1288/3 +f 966/1293/3 963/1290/3 965/1288/3 +f 918/1295/3 919/1286/3 965/1288/3 +f 945/1294/5 956/1302/5 918/1295/5 +f 960/1296/32 947/1346/32 917/1297/32 +f 962/1298/29 966/1293/29 953/1299/29 +f 919/1286/3 918/1295/3 956/1302/3 +f 956/1302/3 958/1347/3 957/1301/3 +f 957/1301/3 959/1306/3 960/1296/3 +f 959/1306/3 961/1348/3 960/1296/3 +f 960/1296/3 919/1286/3 956/1302/3 +f 917/1343/4 916/1342/4 950/1304/4 +f 950/1304/4 952/1349/4 951/1300/4 +f 951/1300/4 953/1299/4 954/1303/4 +f 953/1299/4 955/1350/4 954/1303/4 +f 954/1303/4 917/1343/4 950/1304/4 +f 944/1305/13 948/1326/13 959/1306/13 +f 927/1267/201 928/1351/201 940/1307/201 +f 928/1308/202 926/1275/202 939/1274/202 +f 942/1264/203 943/1310/203 931/1309/203 +f 943/1310/204 941/1268/204 930/1273/204 +f 933/1278/205 934/1313/205 922/1312/205 +f 934/1313/206 932/1276/206 921/1285/206 +f 924/1315/207 925/1352/207 937/1316/207 +f 925/1317/208 923/1344/208 936/1284/208 +f 951/1300/202 952/1353/202 964/1318/202 +f 952/1319/201 950/1291/201 963/1290/201 +f 966/1293/204 967/1321/204 955/1320/204 +f 967/1321/203 965/1288/203 954/1287/203 +f 957/1301/206 958/1324/206 946/1323/206 +f 958/1324/205 956/1302/205 945/1294/205 +f 948/1326/208 949/1354/208 961/1327/208 +f 949/1328/207 947/1346/207 960/1296/207 +f 912/1335/3 920/1329/3 924/1331/3 +f 920/1329/3 922/1355/3 921/1356/3 +f 923/1330/3 920/1329/3 921/1356/3 +f 923/1330/3 925/1357/3 924/1331/3 +f 924/1331/3 913/1336/3 912/1335/3 diff --git a/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj.meta b/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj.meta new file mode 100644 index 0000000..3583531 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj.meta @@ -0,0 +1,113 @@ +fileFormatVersion: 2 +guid: 25f03344dfdd844f88e89487c558fe35 +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/BilliardTable Model.obj + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl b/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl new file mode 100644 index 0000000..427f9a5 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl @@ -0,0 +1,52 @@ +# Blender MTL File: 'BilliardTable.blend' +# Material Count: 5 + +newmtl BlackSurface +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.001547 0.001547 0.001547 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Felt +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.013273 0.201901 0.020515 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Holes +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.054969 0.054969 0.054969 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Lamp +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 2 + +newmtl WhiteSurface +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl.meta b/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl.meta new file mode 100644 index 0000000..be3a524 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5d94495d573e34a16bff9b52dd3ad7e5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/BilliardTable.mtl + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Body.mat b/Assets/Mirror/Examples/Billiards/Table/Body.mat new file mode 100644 index 0000000..d962a43 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Body.mat @@ -0,0 +1,81 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Body + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: + - _EMISSION + m_InvalidKeywords: [] + m_LightmapFlags: 2 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0.2924528, g: 0.2924528, b: 0.2924528, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Body.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Body.mat.meta new file mode 100644 index 0000000..08d7678 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Body.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: d271ebc46b0f74b6fbf2eaab8586fb52 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Body.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Edge.mat b/Assets/Mirror/Examples/Billiards/Table/Edge.mat new file mode 100644 index 0000000..4e4517e --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Edge.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Edge + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.122641504, g: 0.122641504, b: 0.122641504, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Edge.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Edge.mat.meta new file mode 100644 index 0000000..26ef997 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Edge.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 7cfca2b6fd3df4580a0f098abfaf0c64 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Edge.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Felt.mat b/Assets/Mirror/Examples/Billiards/Table/Felt.mat new file mode 100644 index 0000000..83e953e --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Felt.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Felt + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0.62263966, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Felt.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Felt.mat.meta new file mode 100644 index 0000000..218a1d1 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Felt.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 658caa508b3164eeca5e3847394e87a1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Felt.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Holes.mat b/Assets/Mirror/Examples/Billiards/Table/Holes.mat new file mode 100644 index 0000000..0ddc2ba --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Holes.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Holes + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0.2924528, g: 0.2924528, b: 0.2924528, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Holes.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Holes.mat.meta new file mode 100644 index 0000000..f2e9f00 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Holes.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 963c1008ac3af4b1db863a7f7a858eac +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Holes.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Lamp.mat b/Assets/Mirror/Examples/Billiards/Table/Lamp.mat new file mode 100644 index 0000000..adbbdb5 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Lamp.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Lamp + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 2, g: 2, b: 2, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Lamp.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Lamp.mat.meta new file mode 100644 index 0000000..5c71654 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Lamp.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: a5c5ac95f6b544173994adfaae202203 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Lamp.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/License.txt b/Assets/Mirror/Examples/Billiards/Table/License.txt new file mode 100644 index 0000000..8abc41c --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/License.txt @@ -0,0 +1,3 @@ +Billiard Table is under CC0 license. +Created by Jummit @ OpenGameArt: +https://web.archive.org/web/20210923030640/https://opengameart.org/content/futuristic-billiard-table-0 \ No newline at end of file diff --git a/Assets/Mirror/Examples/Billiards/Table/License.txt.meta b/Assets/Mirror/Examples/Billiards/Table/License.txt.meta new file mode 100644 index 0000000..d7ad810 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/License.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 82438f205fdb428db4672ec64657fb8a +timeCreated: 1691690257 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/License.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/Table/Pockets.mat b/Assets/Mirror/Examples/Billiards/Table/Pockets.mat new file mode 100644 index 0000000..3d99a06 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Pockets.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Pockets + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: + - _GLOSSYREFLECTIONS_OFF + - _SPECULARHIGHLIGHTS_OFF + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/Billiards/Table/Pockets.mat.meta b/Assets/Mirror/Examples/Billiards/Table/Pockets.mat.meta new file mode 100644 index 0000000..0ffe8e1 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/Table/Pockets.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 345f064ee294143f9ba2aabdef269c2e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/Table/Pockets.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Billiards/_Readme.txt b/Assets/Mirror/Examples/Billiards/_Readme.txt new file mode 100644 index 0000000..8f4c380 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/_Readme.txt @@ -0,0 +1,18 @@ +Very simple multiplayer Billiards demo. +Mouse drag the white ball to apply force. + +Billiards is surprisingly easy to implement, which makes this a great demo for beginners! + +Hits are sent to the server with a [Command]. +Server simulates physics and sends results back to the client. + +While simple, this approach has a major flaw: latency. +The NetworkManager has a LatencySimulation component to see this on your own computer. +Client actions will always feel a bit delayed while waiting for the server. + +The solution to this is called Prediction: +https://mirror-networking.gitbook.io/docs/manual/general/client-side-prediction + +Notes: +- Red/White ball Rigidbody CollisionMode needs to be ContinousDynamic to avoid white flying through red sometimes. + even 'Continuous' is not enough, we need ContinuousDynamic. \ No newline at end of file diff --git a/Assets/Mirror/Examples/Billiards/_Readme.txt.meta b/Assets/Mirror/Examples/Billiards/_Readme.txt.meta new file mode 100644 index 0000000..914faa5 --- /dev/null +++ b/Assets/Mirror/Examples/Billiards/_Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 36025784d9cce45349813205c53f1153 +timeCreated: 1684039107 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Billiards/_Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted.meta b/Assets/Mirror/Examples/BilliardsPredicted.meta new file mode 100644 index 0000000..eae6239 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d31c223f5c476410b988c7e416495114 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball.meta new file mode 100644 index 0000000..024c073 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3db73e3af7b04b51864106cf8b38b24 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs new file mode 100644 index 0000000..eb4ff22 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs @@ -0,0 +1,42 @@ +// script to handle the table's pocket collisions for resets / destruction. +// predicted objects sometimes have their rigidbodies moved out of them. +// which is why we handle collisions in the table itself, not per-object. +// because here we can check who the rigidbody belongs to more easily. +// ... that's just the best practice at the moment, maybe we can make this +// easier in the future ... +using UnityEngine; + +namespace Mirror.Examples.BilliardsPredicted +{ + public class Pockets : MonoBehaviour + { + void OnTriggerEnter(Collider other) + { + if (!NetworkServer.active) return; + + // the collider may be on a predicted object or on its ghost object. + // find the source first. + if (PredictedRigidbody.IsPredicted(other, out PredictedRigidbody predicted)) + { + // is it a white ball? + if (predicted.TryGetComponent(out WhiteBallPredicted white)) + { + Rigidbody rigidBody = predicted.predictedRigidbody; + rigidBody.position = white.startPosition; +#if UNITY_6000_0_OR_NEWER + rigidBody.linearVelocity = Vector3.zero; +#else + rigidBody.velocity = Vector3.zero; +#endif + } + + // is it a read ball? + if (predicted.GetComponent()) + { + // destroy when entering a pocket. + NetworkServer.Destroy(predicted.gameObject); + } + } + } + } +} diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs.meta new file mode 100644 index 0000000..5f2df9b --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f17c923d118b941fb90a834d87e9ff27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/Pockets.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat new file mode 100644 index 0000000..77a2272 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.92 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0.2971698, b: 0.2971698, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat.meta new file mode 100644 index 0000000..3352a6b --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 919ef8af6341a428380e25d2f2ced7f9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/Red.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs new file mode 100644 index 0000000..352e385 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs @@ -0,0 +1,22 @@ + +using UnityEngine; + +namespace Mirror.Examples.BilliardsPredicted +{ + // keep the empty script so we can find out what type of ball we collided with. + public class RedBallPredicted : NetworkBehaviour + { + /* ball<->pocket collisions are handled by Pockets.cs for now. + because predicted object's rigidbodies are sometimes moved out of them. + which means this script here wouldn't get the collision info while predicting. + which means it's easier to check collisions from the table perspective. + // destroy when entering a pocket. + // there's only one trigger in the scene (the pocket). + [ServerCallback] + void OnTriggerEnter(Collider other) + { + NetworkServer.Destroy(gameObject); + } + */ + } +} diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs.meta new file mode 100644 index 0000000..8a5579b --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3c3384f4b0aaa417abfc3335d2d873c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/RedBallPredicted.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab new file mode 100644 index 0000000..c53ed54 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab @@ -0,0 +1,184 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3429911415116987808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3429911415116987812} + - component: {fileID: 3429911415116987813} + - component: {fileID: 3429911415116987810} + - component: {fileID: 6723567693459418947} + - component: {fileID: 3429911415116987811} + - component: {fileID: -177125271246800426} + - component: {fileID: 5308121378143249733} + - component: {fileID: -8731861437394929722} + m_Layer: 0 + m_Name: RedPredicted + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3429911415116987812 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3429911415116987813 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3429911415116987810 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 919ef8af6341a428380e25d2f2ced7f9, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &6723567693459418947 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 4171706805 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!135 &3429911415116987811 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Material: {fileID: 13400000, guid: b70c4b1c659c647859a8491848d4b145, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &-177125271246800426 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + serializedVersion: 2 + m_Mass: 0.5 + m_Drag: 0.5 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 4 + m_CollisionDetection: 2 +--- !u!114 &5308121378143249733 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3c3384f4b0aaa417abfc3335d2d873c0, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 +--- !u!114 &-8731861437394929722 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d38927cdc6024b9682b5fe9778b9ef99, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + predictedRigidbody: {fileID: -177125271246800426} + mode: 1 + motionSmoothingVelocityThreshold: 0.1 + motionSmoothingAngularVelocityThreshold: 5 + motionSmoothingTimeTolerance: 0.5 + stateHistoryLimit: 32 + recordInterval: 0.05 + onlyRecordChanges: 1 + compareLastFirst: 1 + positionCorrectionThreshold: 0.1 + rotationCorrectionThreshold: 5 + oneFrameAhead: 1 + snapThreshold: 2 + showGhost: 1 + ghostVelocityThreshold: 0.1 + localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320, type: 2} + remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776, type: 2} + checkGhostsEveryNthFrame: 4 + positionInterpolationSpeed: 15 + rotationInterpolationSpeed: 10 + teleportDistanceMultiplier: 10 + reduceSendsWhileIdle: 1 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab.meta new file mode 100644 index 0000000..db0faa0 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ecbb35e2a01c0427ebb0b4b6ed146c70 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/RedPredicted.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat b/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat new file mode 100644 index 0000000..00e46c5 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.93 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat.meta new file mode 100644 index 0000000..e0b5081 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: cc250a30997cc42318e82a6ec42171db +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/White.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs new file mode 100644 index 0000000..4178ea4 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs @@ -0,0 +1,186 @@ +using System; +using UnityEngine; + +namespace Mirror.Examples.BilliardsPredicted +{ + public class WhiteBallPredicted : NetworkBehaviour + { + public LineRenderer dragIndicator; + public float dragTolerance = 1.0f; + public Rigidbody rigidBody; + public float forceMultiplier = 2; + public float maxForce = 40; + + // remember start position to reset to after entering a pocket + internal Vector3 startPosition; + + bool draggingStartedOverObject; + + // cast mouse position on screen to world position + bool MouseToWorld(out Vector3 position) + { + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + Plane plane = new Plane(Vector3.up, transform.position); + if (plane.Raycast(ray, out float distance)) + { + position = ray.GetPoint(distance); + return true; + } + position = default; + return false; + } + + void Awake() + { + startPosition = transform.position; + } + + [ClientCallback] + void Update() + { + // mouse down on the white ball? + if (Input.GetMouseButtonDown(0)) + { + if (MouseToWorld(out Vector3 position)) + { + // allow dragging if mouse is 'close enough'. + // balls are moving so we don't need to be exactly on it. + float distance = Vector3.Distance(position, transform.position); + if (distance <= dragTolerance) + { + // enable drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, transform.position); + dragIndicator.gameObject.SetActive(true); + + draggingStartedOverObject = true; + } + } + } + // mouse button dragging? + else if (Input.GetMouseButton(0)) + { + // cast mouse position to world + if (draggingStartedOverObject && MouseToWorld(out Vector3 current)) + { + // drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, current); + } + } + // mouse button up? + else if (Input.GetMouseButtonUp(0)) + { + // cast mouse position to world + if (draggingStartedOverObject && MouseToWorld(out Vector3 current)) + { + // calculate delta from ball to mouse + // ball may have moved since we started dragging, + // so always use current ball position here. + Vector3 from = transform.position; + + // debug drawing: only works if Gizmos are enabled! + Debug.DrawLine(from, current, Color.white, 2); + + // calculate pending force delta + Vector3 delta = from - current; + Vector3 force = delta * forceMultiplier; + + // there should be a maximum allowed force + force = Vector3.ClampMagnitude(force, maxForce); + + // forward the event to the local player's object. + // the ball isn't part of the local player. + NetworkClient.localPlayer.GetComponent().OnDraggedBall(force); + + // disable drag indicator + dragIndicator.gameObject.SetActive(false); + } + + draggingStartedOverObject = false; + } + } + + // OnMouse callbacks don't work for predicted objects because we need to + // move the collider out of the main object ocassionally. + // besides, having a drag tolerance and not having to click exactly on + // the white ball is nice. + /* + [ClientCallback] + void OnMouseDown() + { + // enable drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, transform.position); + dragIndicator.gameObject.SetActive(true); + } + + [ClientCallback] + void OnMouseDrag() + { + // cast mouse position to world + if (!MouseToWorld(out Vector3 current)) return; + + // drag indicator + dragIndicator.SetPosition(0, transform.position); + dragIndicator.SetPosition(1, current); + } + + [ClientCallback] + void OnMouseUp() + { + // cast mouse position to world + if (!MouseToWorld(out Vector3 current)) return; + + // calculate delta from ball to mouse + // ball may have moved since we started dragging, + // so always use current ball position here. + Vector3 from = transform.position; + + // debug drawing: only works if Gizmos are enabled! + Debug.DrawLine(from, current, Color.white, 2); + + // calculate pending force delta + Vector3 delta = from - current; + Vector3 force = delta * forceMultiplier; + + // there should be a maximum allowed force + force = Vector3.ClampMagnitude(force, maxForce); + + // forward the event to the local player's object. + // the ball isn't part of the local player. + NetworkClient.localPlayer.GetComponent().OnDraggedBall(force); + + // disable drag indicator + dragIndicator.gameObject.SetActive(false); + } + */ + + /* ball<->pocket collisions are handled by Pockets.cs for now. + because predicted object's rigidbodies are sometimes moved out of them. + which means this script here wouldn't get the collision info while predicting. + which means it's easier to check collisions from the table perspective. + // reset position when entering a pocket. + // there's only one trigger in the scene (the pocket). + [ServerCallback] + void OnTriggerEnter(Collider other) + { + rigidBody.position = startPosition; + rigidBody.Sleep(); // reset forces + // GetComponent().RpcTeleport(startPosition); + } + */ + + [ClientCallback] + void OnGUI() + { + // have a button to reply exactly the same force in every hit for easier testing. + if (GUI.Button(new Rect(10, 150, 200, 20), "Hit!")) + { + // hit with a slight angle so the red balls spread out in all directions + Vector3 force = Vector3.ClampMagnitude(new Vector3(10, 0, 600), maxForce); + NetworkClient.localPlayer.GetComponent().OnDraggedBall(force); + } + } + } +} diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs.meta new file mode 100644 index 0000000..44b4608 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8fb3f86b63cef4b2093db683f699a13c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/WhiteBallPredicted.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab new file mode 100644 index 0000000..64e17cc --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab @@ -0,0 +1,318 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &982362981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 982362983} + - component: {fileID: 982362982} + m_Layer: 0 + m_Name: DragIndicator - Line + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &982362983 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 982362981} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 13} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3429911415116987812} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!120 &982362982 +LineRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 982362981} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10306, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_Positions: + - {x: 0, y: 0, z: 0} + - {x: 0, y: 0, z: 1} + m_Parameters: + serializedVersion: 3 + widthMultiplier: 0.1 + widthCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + colorGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 0} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 31418 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + numCornerVertices: 0 + numCapVertices: 0 + alignment: 0 + textureMode: 0 + shadowBias: 0.5 + generateLightingData: 0 + m_UseWorldSpace: 1 + m_Loop: 0 +--- !u!1 &3429911415116987808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3429911415116987812} + - component: {fileID: 3429911415116987813} + - component: {fileID: 3429911415116987810} + - component: {fileID: -1560774411725421365} + - component: {fileID: 3429911415116987811} + - component: {fileID: 1848203816128897140} + - component: {fileID: 6607303410184343467} + - component: {fileID: -2068612481632719751} + m_Layer: 0 + m_Name: WhitePredicted + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3429911415116987812 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 982362983} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3429911415116987813 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3429911415116987810 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: cc250a30997cc42318e82a6ec42171db, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &-1560774411725421365 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1601738520 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!135 &3429911415116987811 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Material: {fileID: 13400000, guid: b70c4b1c659c647859a8491848d4b145, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &1848203816128897140 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + serializedVersion: 2 + m_Mass: 0.5 + m_Drag: 0.5 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 1 + m_Constraints: 4 + m_CollisionDetection: 2 +--- !u!114 &6607303410184343467 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8fb3f86b63cef4b2093db683f699a13c, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + dragIndicator: {fileID: 982362982} + dragTolerance: 1 + rigidBody: {fileID: 1848203816128897140} + forceMultiplier: 2 + maxForce: 40 +--- !u!114 &-2068612481632719751 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3429911415116987808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d38927cdc6024b9682b5fe9778b9ef99, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + predictedRigidbody: {fileID: 1848203816128897140} + mode: 1 + motionSmoothingVelocityThreshold: 0.1 + motionSmoothingAngularVelocityThreshold: 5 + motionSmoothingTimeTolerance: 0.5 + stateHistoryLimit: 32 + recordInterval: 0.05 + onlyRecordChanges: 1 + compareLastFirst: 1 + positionCorrectionThreshold: 0.1 + rotationCorrectionThreshold: 5 + oneFrameAhead: 1 + snapThreshold: 2 + showGhost: 1 + ghostVelocityThreshold: 0.1 + localGhostMaterial: {fileID: 2100000, guid: 411a48b4a197d4924bec3e3809bc9320, type: 2} + remoteGhostMaterial: {fileID: 2100000, guid: 04f0b2088c857414393bab3b80356776, type: 2} + checkGhostsEveryNthFrame: 4 + positionInterpolationSpeed: 15 + rotationInterpolationSpeed: 10 + teleportDistanceMultiplier: 10 + reduceSendsWhileIdle: 1 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab.meta b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab.meta new file mode 100644 index 0000000..e22338e --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 8b8303075efb94c0e9478abfb2e558df +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Ball/WhitePredicted.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity b/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity new file mode 100644 index 0000000..ae09d88 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity @@ -0,0 +1,1410 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936778} + - component: {fileID: 88936779} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.27059805, y: 0.6532815, z: -0.27059805, w: 0.6532815} + m_LocalPosition: {x: -30, y: 25, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 90, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 250 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!114 &88936779 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1001 &156927597 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: -1560774411725421365, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: sceneId + value: 42925857 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987808, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_Name + value: WhitePredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalPosition.z + value: -13 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: 8b8303075efb94c0e9478abfb2e558df, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 8b8303075efb94c0e9478abfb2e558df, type: 3} +--- !u!1001 &361125969 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 11 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 1856985153 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1001 &988968053 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 12 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 3861589763 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1022481212 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 16 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 1907832951 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1036820049 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 13 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 4130529288 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1054702367 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 1408280240 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + - component: {fileID: 1282001523} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 120 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001523} + networkAddress: localhost + maxConnections: 2 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 7529115942715260948, guid: ffab5af8b8b354f8ca8eb7aeaf89dfac, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} + - {fileID: 3429911415116987808, guid: 8b8303075efb94c0e9478abfb2e558df, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 1 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bc654f29862fc2643b948f772ebb9e68, type: 3} + m_Name: + m_EditorClassIdentifier: + color: {r: 1, g: 1, b: 1, a: 1} + padding: 2 + width: 180 + height: 25 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 96b149f511061407fb54895c057b7736, type: 3} + m_Name: + m_EditorClassIdentifier: + wrap: {fileID: 1282001521} + latency: 25 + jitter: 0 + jitterSpeed: 0 + unreliableLoss: 0 + unreliableScramble: 0 +--- !u!1001 &1321391581 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 12 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 965588151 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1647917375 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 14 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 412313944 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1740264579 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 10 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 2313561832 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1763788932 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: 14 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 382588830 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1001 &1927000090 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3429911415116987808, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_Name + value: RedPredicted + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_RootOrder + value: 15 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalPosition.z + value: -2 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3429911415116987812, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6723567693459418947, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, + type: 3} + propertyPath: sceneId + value: 3301516472 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ecbb35e2a01c0427ebb0b4b6ed146c70, type: 3} +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.5 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0, y: 0.9063079, z: -0.42261827, w: 0} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: 180, z: 0} +--- !u!1001 &3539222711505105259 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.y + value: -9.79 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3699661344160954761, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4634620164816052983, guid: dc0a91834ded843aba24753233b8c029, + type: 3} + propertyPath: m_Name + value: Billiard Table + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: dc0a91834ded843aba24753233b8c029, type: 3} diff --git a/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity.meta b/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity.meta new file mode 100644 index 0000000..8ce0f5e --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b18c719cb0805482ca6fc7c2db38ab4b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/MirrorBilliardsPredicted.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Player.meta b/Assets/Mirror/Examples/BilliardsPredicted/Player.meta new file mode 100644 index 0000000..1bc79c7 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Player.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4792af3825b5e47de945b1da8e0037c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs new file mode 100644 index 0000000..19dbc48 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Examples.BilliardsPredicted +{ + // example input for this exact demo. + // not general purpose yet. + public struct PlayerInput + { + public double timestamp; + public Vector3 force; + + public PlayerInput(double timestamp, Vector3 force) + { + this.timestamp = timestamp; + this.force = force; + } + } + + public class PlayerPredicted : NetworkBehaviour + { + // white ball component + WhiteBallPredicted whiteBall; + + void Awake() + { + // find the white ball once +#if UNITY_2022_2_OR_NEWER + whiteBall = FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + whiteBall = FindObjectOfType(); +#endif + } + + // apply force to white ball. + // common function to ensure we apply it the same way on server & client! + void ApplyForceToWhite(Vector3 force) + { + // https://docs.unity3d.com/2021.3/Documentation/ScriptReference/Rigidbody.AddForce.html + // this is buffered until the next FixedUpdate. + + // get the white ball's Rigidbody. + // prediction sometimes moves this out of the object for a while, + // so we need to grab it this way: + Rigidbody rb = whiteBall.GetComponent().predictedRigidbody; + + // AddForce has different force modes, see this excellent diagram: + // https://www.reddit.com/r/Unity3D/comments/psukm1/know_the_difference_between_forcemodes_a_little/ + // for prediction it's extremely important(!) to apply the correct mode: + // 'Force' makes server & client drift significantly here + // 'Impulse' is correct usage with significantly less drift + rb.AddForce(force, ForceMode.Impulse); + } + + // called when the local player dragged the white ball. + // we reuse the white ball's OnMouseDrag and forward the event to here. + public void OnDraggedBall(Vector3 force) + { + // apply force locally immediately + ApplyForceToWhite(force); + + // apply on server as well. + // not necessary in host mode, otherwise we would apply it twice. + if (!isServer) CmdApplyForce(force); + } + + // while prediction is applied on clients immediately, + // we still want to validate every input on the server and reject it if necessary. + // this way we can latency free yet cheat safe movement. + // this should include a certain tolerance so players aren't hard corrected + // for their local movement all the time. + // TODO this should be on some kind of base class for reuse, but perhaps independent of parameters? + bool IsValidMove(Vector3 force) => true; + + // TODO send over unreliable with ack, notify, etc. later + [Command] + void CmdApplyForce(Vector3 force) + { + if (!IsValidMove(force)) + { + Debug.Log($"Server rejected move: {force}"); + return; + } + + // apply force + ApplyForceToWhite(force); + } + } +} diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs.meta b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs.meta new file mode 100644 index 0000000..edce3cd --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 79c6ff7781e8c4174b07ea7e905f62b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab new file mode 100644 index 0000000..c6ff550 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab @@ -0,0 +1,66 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7529115942715260948 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1534822232247476853} + - component: {fileID: 1279227879756014839} + - component: {fileID: -1702612885512365273} + m_Layer: 0 + m_Name: PlayerPredicted + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1534822232247476853 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7529115942715260948} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1279227879756014839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7529115942715260948} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 4028108460 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-1702612885512365273 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7529115942715260948} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 79c6ff7781e8c4174b07ea7e905f62b2, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab.meta b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab.meta new file mode 100644 index 0000000..976c6c6 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ffab5af8b8b354f8ca8eb7aeaf89dfac +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/Player/PlayerPredicted.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt b/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt new file mode 100644 index 0000000..4e0a04c --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt @@ -0,0 +1,19 @@ +Advanced multiplayer Billiards demo with Prediction. + +Please read this first: +https://mirror-networking.gitbook.io/docs/manual/general/client-side-prediction + +Mouse drag the white ball to apply force. +PredictedRigidbody syncInterval is intentionally set pretty high so we can see when it corrects. + +If you are a beginner, start with the basic Billiards demo instead. +If you are advanced, this demo shows how to use Mirror's prediction features for physics / FPS games. + +Billiards is a great example to try our Prediction algorithm, it works extremely well here! + +=> We use 'Fast' Prediction mode for Billiards because we want to see exact collisions with balls/walls. +=> 'Smooth' mode would look too soft, with balls changing direction even before touching other balls/walls. + +Notes: +- Red/White ball Rigidbody CollisionMode needs to be ContinousDynamic to avoid white flying through red sometimes. + even 'Continous' is not enough, we need ContinousDynamic. diff --git a/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt.meta b/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt.meta new file mode 100644 index 0000000..5ce49f8 --- /dev/null +++ b/Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e88568e61917a49d5957d51c4f8fb239 +timeCreated: 1684039107 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/BilliardsPredicted/_Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU.meta b/Assets/Mirror/Examples/CCU.meta new file mode 100644 index 0000000..667a616 --- /dev/null +++ b/Assets/Mirror/Examples/CCU.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1224ecd334304d359f5930d0e7d85fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs new file mode 100644 index 0000000..3891eee --- /dev/null +++ b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs @@ -0,0 +1,93 @@ +using UnityEngine; + +namespace Mirror.Examples.CCU +{ + [AddComponentMenu("")] + public class CCUNetworkManager : NetworkManager + { + [Header("Spawns")] + public int spawnAmount = 10_000; + public float interleave = 1; + public GameObject spawnPrefab; + + // player spawn positions should be spread across the world. + // not all at one place. + // but _some_ at the same place. + // => deterministic random is ideal + [Range(0, 1)] public float spawnPositionRatio = 0.01f; + + System.Random random = new System.Random(42); + + void SpawnAll() + { + // clear previous player spawn positions in case we start twice + foreach (Transform position in startPositions) + Destroy(position.gameObject); + + startPositions.Clear(); + + // calculate sqrt so we can spawn N * N = Amount + float sqrt = Mathf.Sqrt(spawnAmount); + + // calculate spawn xz start positions + // based on spawnAmount * distance + float offset = -sqrt / 2 * interleave; + + // spawn exactly the amount, not one more. + int spawned = 0; + for (int spawnX = 0; spawnX < sqrt; ++spawnX) + { + for (int spawnZ = 0; spawnZ < sqrt; ++spawnZ) + { + // spawn exactly the amount, not any more + // (our sqrt method isn't 100% precise) + if (spawned < spawnAmount) + { + // spawn & position + GameObject go = Instantiate(spawnPrefab); + float x = offset + spawnX * interleave; + float z = offset + spawnZ * interleave; + Vector3 position = new Vector3(x, 0, z); + go.transform.position = position; + + // spawn + NetworkServer.Spawn(go); + ++spawned; + + // add random spawn position for players. + // don't have them all in the same place. + if (random.NextDouble() <= spawnPositionRatio) + { + GameObject spawnGO = new GameObject("Spawn"); + spawnGO.transform.position = position; + spawnGO.AddComponent(); + } + } + } + } + } + + // overwrite random spawn position selection: + // - needs to be deterministic so every CCU test results in the same + // - needs to be random so not only are the spawn positions spread out + // randomly, we also have a random amount of players per spawn position + public override Transform GetStartPosition() + { + // first remove any dead transforms + startPositions.RemoveAll(t => t == null); + + if (startPositions.Count == 0) + return null; + + // pick a random one + int index = random.Next(0, startPositions.Count); // DETERMINISTIC + return startPositions[index]; + } + + public override void OnStartServer() + { + base.OnStartServer(); + SpawnAll(); + } + } +} diff --git a/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta new file mode 100644 index 0000000..9ba51c4 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/CCUNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b0ff29cd45bcd43128c4cc79f25fd658 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/CCUNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/MirrorCCU.unity b/Assets/Mirror/Examples/CCU/MirrorCCU.unity new file mode 100644 index 0000000..5ce2782 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/MirrorCCU.unity @@ -0,0 +1,541 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 35 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956} + m_LocalPosition: {x: 0, y: 600, z: -800} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + - component: {fileID: 1282001523} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b0ff29cd45bcd43128c4cc79f25fd658, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 449802645721213856, guid: 614e28b6213c14195b8661c153bf4ee4, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 449802645721213856, guid: d0f3b049f6bef4cc6930c57a2146ca52, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + spawnAmount: 10000 + interleave: 10 + spawnPrefab: {fileID: 449802645721213856, guid: d0f3b049f6bef4cc6930c57a2146ca52, + type: 3} + spawnPositionRatio: 0.01 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 39adc6e09d5544ed955a50ce8600355a, type: 3} + m_Name: + m_EditorClassIdentifier: + visRange: 30 + rebuildInterval: 1 + checkMethod: 0 + showSlider: 0 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6d7da4e566d24ea7b0e12178d934b648, type: 3} + m_Name: + m_EditorClassIdentifier: + clientIntervalReceivedPackets: 0 + clientIntervalReceivedBytes: 0 + clientIntervalSentPackets: 0 + clientIntervalSentBytes: 0 + clientReceivedPacketsPerSecond: 0 + clientReceivedBytesPerSecond: 0 + clientSentPacketsPerSecond: 0 + clientSentBytesPerSecond: 0 + serverIntervalReceivedPackets: 0 + serverIntervalReceivedBytes: 0 + serverIntervalSentPackets: 0 + serverIntervalSentBytes: 0 + serverReceivedPacketsPerSecond: 0 + serverReceivedBytesPerSecond: 0 + serverSentPacketsPerSecond: 0 + serverSentBytesPerSecond: 0 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/CCU/MirrorCCU.unity.meta b/Assets/Mirror/Examples/CCU/MirrorCCU.unity.meta new file mode 100644 index 0000000..b60bd3d --- /dev/null +++ b/Assets/Mirror/Examples/CCU/MirrorCCU.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a692de27a26e74566b797df05d9b3385 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/MirrorCCU.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Monster.cs b/Assets/Mirror/Examples/CCU/Monster.cs new file mode 100644 index 0000000..420c487 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Monster.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +namespace Mirror.Examples.CCU +{ + public class Monster : NetworkBehaviour + { + public float speed = 1; + public float movementProbability = 0.5f; + public float movementDistance = 20; + + bool moving; + Vector3 start; + Vector3 destination; + + // cache .transform for benchmark demo. + // Component.get_transform shows in profiler otherwise. + Transform tf; + + public override void OnStartServer() + { + tf = transform; + start = tf.position; + } + + [ServerCallback] + void Update() + { + if (moving) + { + if (Vector3.Distance(tf.position, destination) <= 0.01f) + { + moving = false; + } + else + { + tf.position = Vector3.MoveTowards(tf.position, destination, speed * Time.deltaTime); + } + } + else + { + float r = Random.value; + if (r < movementProbability * Time.deltaTime) + { + Vector2 circlePos = Random.insideUnitCircle; + Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); + + // set destination on random pos in a circle around start. + // (don't want to wander off) + destination = start + dir * movementDistance; + moving = true; + } + } + } + } +} diff --git a/Assets/Mirror/Examples/CCU/Monster.cs.meta b/Assets/Mirror/Examples/CCU/Monster.cs.meta new file mode 100644 index 0000000..0399dbf --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Monster.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b3a6fbf45e1c94ce6b2c1a2d08519a11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Monster.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Monster.prefab b/Assets/Mirror/Examples/CCU/Monster.prefab new file mode 100644 index 0000000..d768f46 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Monster.prefab @@ -0,0 +1,152 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: -3181616459286004871} + m_Layer: 0 + m_Name: Monster + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 451c5da2c5056496297cffba02216286, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3813491927 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2697352357490696306} + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 0 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 1 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-3181616459286004871 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b3a6fbf45e1c94ce6b2c1a2d08519a11, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + speed: 1 + movementProbability: 0.5 + movementDistance: 20 diff --git a/Assets/Mirror/Examples/CCU/Monster.prefab.meta b/Assets/Mirror/Examples/CCU/Monster.prefab.meta new file mode 100644 index 0000000..455730e --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Monster.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d0f3b049f6bef4cc6930c57a2146ca52 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Monster.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Player.cs b/Assets/Mirror/Examples/CCU/Player.cs new file mode 100644 index 0000000..dd98ca8 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Player.cs @@ -0,0 +1,99 @@ +using UnityEngine; + +namespace Mirror.Examples.CCU +{ + public class Player : NetworkBehaviour + { + public Vector3 cameraOffset = new Vector3(0, 40, -40); + + // automated movement. + // player may switch to manual movement any time + [Header("Automated Movement")] + public bool autoMove = true; + public float autoSpeed = 2; + public float movementProbability = 0.5f; + public float movementDistance = 20; + bool moving; + Vector3 start; + Vector3 destination; + + [Header("Manual Movement")] + public float manualSpeed = 10; + + // cache .transform for benchmark demo. + // Component.get_transform shows in profiler otherwise. + Transform tf; + + public override void OnStartLocalPlayer() + { + tf = transform; + start = tf.position; + + // make camera follow + Camera.main.transform.SetParent(transform, false); + Camera.main.transform.localPosition = cameraOffset; + } + + public override void OnStopLocalPlayer() + { + // free the camera so we don't destroy it too + Camera.main.transform.SetParent(null, true); + } + + void AutoMove() + { + if (moving) + { + if (Vector3.Distance(tf.position, destination) <= 0.01f) + { + moving = false; + } + else + { + tf.position = Vector3.MoveTowards(tf.position, destination, autoSpeed * Time.deltaTime); + } + } + else + { + float r = Random.value; + if (r < movementProbability * Time.deltaTime) + { + // calculate a random position in a circle + float circleX = Mathf.Cos(Random.value * Mathf.PI); + float circleZ = Mathf.Sin(Random.value * Mathf.PI); + Vector2 circlePos = new Vector2(circleX, circleZ); + Vector3 dir = new Vector3(circlePos.x, 0, circlePos.y); + + // set destination on random pos in a circle around start. + // (don't want to wander off) + destination = start + dir * movementDistance; + moving = true; + } + } + } + + void ManualMove() + { + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + Vector3 direction = new Vector3(h, 0, v); + transform.position += direction.normalized * (Time.deltaTime * manualSpeed); + } + + static bool Interrupted() => + Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0; + + void Update() + { + if (!isLocalPlayer) return; + + // player may interrupt auto movement to switch to manual + if (Interrupted()) autoMove = false; + + // move + if (autoMove) AutoMove(); + else ManualMove(); + } + } +} diff --git a/Assets/Mirror/Examples/CCU/Player.cs.meta b/Assets/Mirror/Examples/CCU/Player.cs.meta new file mode 100644 index 0000000..c573c17 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Player.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2c936c3d1cc664f15a92190fc35fd7dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Player.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Player.prefab b/Assets/Mirror/Examples/CCU/Player.prefab new file mode 100644 index 0000000..720b699 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Player.prefab @@ -0,0 +1,175 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &449802645721213856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2697352357490696306} + - component: {fileID: 8695142844114820487} + - component: {fileID: 6692327599609520039} + - component: {fileID: 1078519278818213949} + - component: {fileID: 3679374677650722848} + - component: {fileID: 8691745481282286165} + - component: {fileID: 8079286830074380037} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2697352357490696306 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8695142844114820487 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6692327599609520039 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8f106e5c9e34da28ad9cee6edb2255, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1078519278818213949 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 561134667 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3679374677650722848 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2697352357490696306} + syncPosition: 1 + syncRotation: 0 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 0 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &8691745481282286165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2c936c3d1cc664f15a92190fc35fd7dd, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + cameraOffset: {x: 0, y: 40, z: -40} + autoMove: 1 + autoSpeed: 2 + movementProbability: 0.5 + movementDistance: 20 + manualSpeed: 10 +--- !u!114 &8079286830074380037 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 449802645721213856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ba360e4ff6b44fc6898f56322b90c6c8, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 1 + syncInterval: 0.1 + sendInterval: 1 + showGui: 0 + hotKey: 292 + passwordFile: remote_statistics.txt diff --git a/Assets/Mirror/Examples/CCU/Player.prefab.meta b/Assets/Mirror/Examples/CCU/Player.prefab.meta new file mode 100644 index 0000000..f4dbddd --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 614e28b6213c14195b8661c153bf4ee4 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Readme.txt b/Assets/Mirror/Examples/CCU/Readme.txt new file mode 100644 index 0000000..673d30e --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Readme.txt @@ -0,0 +1,9 @@ +This is used for CCU tests. +White = players, Red = monsters. + +In NetworkManager: +- set the server's IP/Port +- enable 'auto start headless server', build server binary. +- enable 'auto connect headless client', build client binary. + +Launch 1 server with N clients. \ No newline at end of file diff --git a/Assets/Mirror/Examples/CCU/Readme.txt.meta b/Assets/Mirror/Examples/CCU/Readme.txt.meta new file mode 100644 index 0000000..8e2afe3 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Readme.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 56dba4f891064da0a2dd9ccbe1f02899 +timeCreated: 1678260514 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Readme.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/Red.mat b/Assets/Mirror/Examples/CCU/Red.mat new file mode 100644 index 0000000..5c24968 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Red.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Red + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/CCU/Red.mat.meta b/Assets/Mirror/Examples/CCU/Red.mat.meta new file mode 100644 index 0000000..4fc2373 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/Red.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 7b742246ea1d249358a8a8e039bd4b17 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/Red.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CCU/White.mat b/Assets/Mirror/Examples/CCU/White.mat new file mode 100644 index 0000000..aaf3087 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/White.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: White + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 0 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0.3254902, g: 0.3254902, b: 0.3254902, a: 1} diff --git a/Assets/Mirror/Examples/CCU/White.mat.meta b/Assets/Mirror/Examples/CCU/White.mat.meta new file mode 100644 index 0000000..67fc3c8 --- /dev/null +++ b/Assets/Mirror/Examples/CCU/White.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: ae32f0609a5e9453b95ec3b9e28c2ac8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CCU/White.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection.meta b/Assets/Mirror/Examples/CharacterSelection.meta new file mode 100644 index 0000000..2d5dbea --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1cc43bc1eac5249af904498f94e6c31b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials.meta b/Assets/Mirror/Examples/CharacterSelection/Materials.meta new file mode 100644 index 0000000..d0bba38 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dabea68aaa21b43e0a987a37a3782033 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat new file mode 100644 index 0000000..1281b9b --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialBlack + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat.meta new file mode 100644 index 0000000..cc86bad --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 0f0dbf645ce2a45b390c0514e3758988 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBlack.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat new file mode 100644 index 0000000..c94a344 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialBrown + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.5660378, g: 0.37453502, b: 0.2322891, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat.meta new file mode 100644 index 0000000..528fe81 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: b976126dcdf3a407b86a1488c2f05b98 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialBrown.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat new file mode 100644 index 0000000..9e1bc69 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialDesert + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.7169812, g: 0.6441445, b: 0.34834465, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat.meta new file mode 100644 index 0000000..535af7a --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: c563271c8eff8458a9d61b9a48b9cb12 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialDesert.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat new file mode 100644 index 0000000..d4375a8 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialFloor + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 90, y: 90} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 1d05f8485741f4d4ca94e613ba38db65, type: 3} + m_Scale: {x: 90, y: 90} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.01 + - _GlossyReflections: 1 + - _Metallic: 1 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.8396226, g: 0.8396226, b: 0.8396226, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat.meta new file mode 100644 index 0000000..d1e5712 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 5d4646112e9b746a9b531366427f3218 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialFloor.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat new file mode 100644 index 0000000..b15c3ef --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialGold + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0.68598413, b: 0, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat.meta new file mode 100644 index 0000000..abaa417 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 4501a33f89e954d2aacce3ee73c43903 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGold.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat new file mode 100644 index 0000000..7bbc1eb --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialGreenDark + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.16731386, g: 0.3207547, b: 0.16491634, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat.meta new file mode 100644 index 0000000..7189479 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: b4814d6b577aa424991905946c0fe6dc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialGreenDark.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat new file mode 100644 index 0000000..dfe1031 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialIcon1 + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat.meta new file mode 100644 index 0000000..9d63b31 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 8571b3e10d2fa4348b4df0dbdc082c32 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialIcon1.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat new file mode 100644 index 0000000..b8f1b27 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialRed + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat.meta new file mode 100644 index 0000000..3afe76b --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 0cb2aedfe1c0146808538c1b8ae2b1ab +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialRed.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat new file mode 100644 index 0000000..b93b158 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialSilver + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.7529412, g: 0.7529412, b: 0.7529412, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat.meta new file mode 100644 index 0000000..486db66 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 6a1d409bf7eea44168084517c7ee81cf +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialSilver.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat new file mode 100644 index 0000000..62793cd --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialWhite + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 0.0627451} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat.meta b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat.meta new file mode 100644 index 0000000..0e5f071 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 0eb01134dad314f879704d594ca8a7b2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Materials/MaterialWhite.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity new file mode 100644 index 0000000..9048554 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity @@ -0,0 +1,3307 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000000, guid: 3918ae325cb5947a88ec1370790f46cc, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &12937795 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 12937796} + - component: {fileID: 12937798} + - component: {fileID: 12937797} + m_Layer: 5 + m_Name: Image Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &12937796 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1732781857} + m_Father: {fileID: 1176522086} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 290} + m_SizeDelta: {x: 0.000022074748, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &12937797 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &12937798 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_CullTransparentMesh: 1 +--- !u!1 &82285611 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 82285612} + - component: {fileID: 82285614} + - component: {fileID: 82285613} + m_Layer: 5 + m_Name: Text Abilities + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &82285612 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: -41.62291} + m_SizeDelta: {x: 512.3848, y: 158.2005} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &82285613 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Abilities: + + Likes to party' +--- !u!222 &82285614 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_CullTransparentMesh: 1 +--- !u!1 &121663634 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 121663635} + - component: {fileID: 121663637} + - component: {fileID: 121663636} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &121663635 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1455489536} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &121663636 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &121663637 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_CullTransparentMesh: 1 +--- !u!1 &177909552 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 177909553} + - component: {fileID: 177909556} + - component: {fileID: 177909555} + - component: {fileID: 177909554} + m_Layer: 5 + m_Name: Button Go + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &177909553 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 743308479} + m_Father: {fileID: 1487444786} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -0.00012207031, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0} +--- !u!114 &177909554 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 177909555} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &177909555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &177909556 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_CullTransparentMesh: 1 +--- !u!1 &260596653 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 260596655} + - component: {fileID: 260596654} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &260596654 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 260596653} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &260596655 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 260596653} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 526073996} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &337018481 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 337018482} + - component: {fileID: 337018484} + - component: {fileID: 337018483} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &337018482 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1455489536} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &337018483 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter player name... +--- !u!222 &337018484 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_CullTransparentMesh: 1 +--- !u!1 &387810209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 387810210} + - component: {fileID: 387810212} + - component: {fileID: 387810211} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &387810210 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1949358294} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &387810211 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 9e7771f048fdf40839b6ee9dbacad67c, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &387810212 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_CullTransparentMesh: 1 +--- !u!1 &390222343 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 390222344} + - component: {fileID: 390222345} + m_Layer: 0 + m_Name: NPS (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &390222344 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 390222343} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &390222345 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 390222343} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &526073995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 526073996} + m_Layer: 0 + m_Name: SceneObjects + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &526073996 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 526073995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1738721968} + - {fileID: 260596655} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &556161874 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 556161875} + - component: {fileID: 556161877} + - component: {fileID: 556161876} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &556161875 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1705599351} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &556161876 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 6 + m_MaxSize: 60 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: '>' +--- !u!222 &556161877 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_CullTransparentMesh: 1 +--- !u!1 &571598368 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 571598369} + - component: {fileID: 571598370} + m_Layer: 0 + m_Name: NPS (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &571598369 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571598368} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &571598370 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571598368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &589665224 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 589665225} + - component: {fileID: 589665227} + - component: {fileID: 589665226} + m_Layer: 5 + m_Name: Image Title (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &589665225 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 669360967} + m_Father: {fileID: 1176522086} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -52.369, y: -399} + m_SizeDelta: {x: -104.74, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &589665226 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &589665227 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_CullTransparentMesh: 1 +--- !u!1 &651460150 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 651460153} + - component: {fileID: 651460152} + - component: {fileID: 651460151} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &651460151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &651460152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &651460153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &669360966 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 669360967} + - component: {fileID: 669360969} + - component: {fileID: 669360968} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &669360967 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 589665225} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &669360968 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title +--- !u!222 &669360969 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_CullTransparentMesh: 1 +--- !u!1 &694584905 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 694584906} + - component: {fileID: 694584908} + - component: {fileID: 694584907} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &694584906 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1200597393} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &694584907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 69c30291565a1407abc7ca25da395ea9, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &694584908 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_CullTransparentMesh: 1 +--- !u!1 &743308478 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 743308479} + - component: {fileID: 743308481} + - component: {fileID: 743308480} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &743308479 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 177909553} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &743308480 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Go ! +--- !u!222 &743308481 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_CullTransparentMesh: 1 +--- !u!1 &866712465 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 866712466} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &866712466 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 866712465} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1444013441} + - {fileID: 571598369} + - {fileID: 390222344} + - {fileID: 1442321499} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &898306491 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 898306492} + - component: {fileID: 898306494} + - component: {fileID: 898306493} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &898306492 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1200597393} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &898306493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: R +--- !u!222 &898306494 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_CullTransparentMesh: 1 +--- !u!1 &1027181964 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1027181965} + - component: {fileID: 1027181968} + - component: {fileID: 1027181967} + - component: {fileID: 1027181966} + m_Layer: 5 + m_Name: Button Colour + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1027181965 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1347574005} + - {fileID: 1302055873} + m_Father: {fileID: 1487444786} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -447, y: -183} + m_SizeDelta: {x: 250, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1027181966 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1027181967} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1027181967 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1027181968 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_CullTransparentMesh: 1 +--- !u!1 &1176522085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1176522086} + - component: {fileID: 1176522088} + - component: {fileID: 1176522087} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1176522086 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 12937796} + - {fileID: 1605805618} + - {fileID: 1350751291} + - {fileID: 1526182834} + - {fileID: 82285612} + - {fileID: 589665225} + - {fileID: 1455489536} + m_Father: {fileID: 1487444786} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -100, y: 0} + m_SizeDelta: {x: 600, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1176522087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1176522088 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_CullTransparentMesh: 1 +--- !u!1 &1200597392 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1200597393} + - component: {fileID: 1200597396} + - component: {fileID: 1200597395} + - component: {fileID: 1200597394} + m_Layer: 5 + m_Name: Button Colour Reset + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1200597393 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 898306492} + - {fileID: 694584906} + m_Father: {fileID: 1487444786} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -334, y: -183.00003} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1200597394 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1200597395} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1200597395 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1200597396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_CullTransparentMesh: 1 +--- !u!1 &1302055872 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1302055873} + - component: {fileID: 1302055875} + - component: {fileID: 1302055874} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1302055873 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027181965} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0, y: 0.5} +--- !u!114 &1302055874 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 13ba34da9011744c884f459ce4699444, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1302055875 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_CullTransparentMesh: 1 +--- !u!1 &1347574004 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1347574005} + - component: {fileID: 1347574007} + - component: {fileID: 1347574006} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1347574005 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027181965} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0.000030517578, y: 0} + m_SizeDelta: {x: 137.1865, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1347574006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Colour +--- !u!222 &1347574007 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_CullTransparentMesh: 1 +--- !u!1 &1350751290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1350751291} + - component: {fileID: 1350751293} + - component: {fileID: 1350751292} + m_Layer: 5 + m_Name: Text Speed + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1350751291 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 137} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1350751292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Speed: 5' +--- !u!222 &1350751293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_CullTransparentMesh: 1 +--- !u!1 &1442321498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1442321499} + - component: {fileID: 1442321500} + m_Layer: 0 + m_Name: NPS (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1442321499 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442321498} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1442321500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442321498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1444013440 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1444013441} + - component: {fileID: 1444013442} + m_Layer: 0 + m_Name: NPS (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1444013441 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1444013440} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1444013442 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1444013440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1448196615 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1448196619} + - component: {fileID: 1448196618} + - component: {fileID: 1448196617} + - component: {fileID: 1448196616} + m_Layer: 0 + m_Name: Floor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!64 &1448196616 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1448196617 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5d4646112e9b746a9b531366427f3218, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1448196618 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1448196619 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: -1, z: 0} + m_LocalScale: {x: 15, y: 1, z: 15} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1455489535 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1455489536} + - component: {fileID: 1455489539} + - component: {fileID: 1455489538} + - component: {fileID: 1455489537} + m_Layer: 5 + m_Name: InputField (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1455489536 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 337018482} + - {fileID: 121663635} + m_Father: {fileID: 1176522086} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: -290} + m_SizeDelta: {x: 0, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1455489537 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1455489538} + m_TextComponent: {fileID: 121663636} + m_Placeholder: {fileID: 337018483} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1455489538 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1455489539 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_CullTransparentMesh: 1 +--- !u!1 &1487444781 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1487444786} + - component: {fileID: 1487444785} + - component: {fileID: 1487444784} + - component: {fileID: 1487444783} + - component: {fileID: 1487444782} + m_Layer: 5 + m_Name: SceneCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1487444782 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f45e025c29e20480cb3d9ab86918814a, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonCharacterSelection: {fileID: 1949358291} + characterSelectionObject: {fileID: 1688373239} + sceneObjects: {fileID: 526073995} + cameraObject: {fileID: 1738721965} +--- !u!114 &1487444783 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1487444784 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 1 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1487444785 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1487444786 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1949358294} + - {fileID: 1705599351} + - {fileID: 177909553} + - {fileID: 1176522086} + - {fileID: 1027181965} + - {fileID: 1200597393} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1512997440 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1512997444} + - component: {fileID: 1512997443} + - component: {fileID: 1512997442} + - component: {fileID: 1512997441} + m_Layer: 0 + m_Name: NetworkManagerCharacterSelection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1512997441 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1512997442 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1512997443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 98c582433a349434990d734c5586d722, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1512997442} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 1 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 0} + autoCreatePlayer: 0 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 3074504447143314537, guid: f574d1625ad4549bba64a6edf31b4d10, type: 3} + - {fileID: 2320049526911491159, guid: 59ffef73ea4ec43c09cd00a5135ca8f1, type: 3} + - {fileID: 9105303183089727057, guid: c9bc5d2c4dbfe45698e8df60415a0b9b, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + SpawnAsCharacter: 1 +--- !u!4 &1512997444 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1526182833 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1526182834} + - component: {fileID: 1526182836} + - component: {fileID: 1526182835} + m_Layer: 5 + m_Name: Text Attack + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1526182834 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 73} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1526182835 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Attack: 1' +--- !u!222 &1526182836 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_CullTransparentMesh: 1 +--- !u!1 &1605805617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1605805618} + - component: {fileID: 1605805620} + - component: {fileID: 1605805619} + m_Layer: 5 + m_Name: Text Health + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1605805618 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 204} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1605805619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Health: 10' +--- !u!222 &1605805620 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_CullTransparentMesh: 1 +--- !u!1001 &1688373238 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6961198749896887833, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: sceneReferencer + value: + objectReference: {fileID: 1487444782} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.x + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.y + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.z + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_Name + value: CharacterSelction + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 55ecb772328404c428beb4e2cf51044a, type: 3} +--- !u!1 &1688373239 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + m_PrefabInstance: {fileID: 1688373238} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1705599350 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1705599351} + - component: {fileID: 1705599354} + - component: {fileID: 1705599353} + - component: {fileID: 1705599352} + m_Layer: 5 + m_Name: Button Next Character + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1705599351 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 556161875} + m_Father: {fileID: 1487444786} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1705599352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1705599353} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1705599353 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1705599354 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_CullTransparentMesh: 1 +--- !u!1 &1732781856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1732781857} + - component: {fileID: 1732781859} + - component: {fileID: 1732781858} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1732781857 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 12937796} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1732781858 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title +--- !u!222 &1732781859 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_CullTransparentMesh: 1 +--- !u!1 &1738721965 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1738721968} + - component: {fileID: 1738721967} + - component: {fileID: 1738721966} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1738721966 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_Enabled: 1 +--- !u!20 &1738721967 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.5, g: 0.5, b: 0.5, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1738721968 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 526073996} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1828506693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1828506694} + - component: {fileID: 1828506696} + - component: {fileID: 1828506695} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1828506694 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1949358294} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1828506695 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X +--- !u!222 &1828506696 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_CullTransparentMesh: 1 +--- !u!1 &1949358290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1949358294} + - component: {fileID: 1949358293} + - component: {fileID: 1949358292} + - component: {fileID: 1949358291} + m_Layer: 5 + m_Name: Button Character Selection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1949358291 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1949358292} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1949358292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1949358293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_CullTransparentMesh: 1 +--- !u!224 &1949358294 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1828506694} + - {fileID: 387810210} + m_Father: {fileID: 1487444786} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 200} + m_Pivot: {x: 1, y: 1} +--- !u!1001 &3266697494893471161 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.x + value: -3.694591 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.44966963 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.z + value: 2.4900506 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766767, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_Name + value: CharacterData + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6acf49d76d0eb47c08e908da71d52859, type: 3} diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity.meta b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity.meta new file mode 100644 index 0000000..c14cebe --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9619a16fe963d4deb9b5821f4475c606 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelection.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity new file mode 100644 index 0000000..d8d480e --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity @@ -0,0 +1,3308 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000000, guid: 3918ae325cb5947a88ec1370790f46cc, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &12937795 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 12937796} + - component: {fileID: 12937798} + - component: {fileID: 12937797} + m_Layer: 5 + m_Name: Image Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &12937796 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1732781857} + m_Father: {fileID: 1176522086} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 290} + m_SizeDelta: {x: 0.000022074748, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &12937797 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &12937798 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 12937795} + m_CullTransparentMesh: 1 +--- !u!1 &82285611 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 82285612} + - component: {fileID: 82285614} + - component: {fileID: 82285613} + m_Layer: 5 + m_Name: Text Abilities + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &82285612 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: -41.62291} + m_SizeDelta: {x: 512.3848, y: 158.2005} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &82285613 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Abilities: + + Likes to party' +--- !u!222 &82285614 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 82285611} + m_CullTransparentMesh: 1 +--- !u!1 &121663634 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 121663635} + - component: {fileID: 121663637} + - component: {fileID: 121663636} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &121663635 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1455489536} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &121663636 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &121663637 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121663634} + m_CullTransparentMesh: 1 +--- !u!1 &177909552 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 177909553} + - component: {fileID: 177909556} + - component: {fileID: 177909555} + - component: {fileID: 177909554} + m_Layer: 5 + m_Name: Button Go + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &177909553 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 743308479} + m_Father: {fileID: 1487444786} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -0.00012207031, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0} +--- !u!114 &177909554 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 177909555} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &177909555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &177909556 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 177909552} + m_CullTransparentMesh: 1 +--- !u!1 &260596653 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 260596655} + - component: {fileID: 260596654} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &260596654 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 260596653} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &260596655 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 260596653} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 526073996} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &337018481 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 337018482} + - component: {fileID: 337018484} + - component: {fileID: 337018483} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &337018482 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1455489536} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &337018483 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter player name... +--- !u!222 &337018484 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 337018481} + m_CullTransparentMesh: 1 +--- !u!1 &387810209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 387810210} + - component: {fileID: 387810212} + - component: {fileID: 387810211} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &387810210 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1949358294} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &387810211 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 9e7771f048fdf40839b6ee9dbacad67c, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &387810212 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 387810209} + m_CullTransparentMesh: 1 +--- !u!1 &390222343 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 390222344} + - component: {fileID: 390222345} + m_Layer: 0 + m_Name: NPS (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &390222344 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 390222343} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &390222345 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 390222343} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &526073995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 526073996} + m_Layer: 0 + m_Name: SceneObjects + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &526073996 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 526073995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1738721968} + - {fileID: 260596655} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &556161874 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 556161875} + - component: {fileID: 556161877} + - component: {fileID: 556161876} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &556161875 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1705599351} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &556161876 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 6 + m_MaxSize: 60 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: '>' +--- !u!222 &556161877 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 556161874} + m_CullTransparentMesh: 1 +--- !u!1 &571598368 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 571598369} + - component: {fileID: 571598370} + m_Layer: 0 + m_Name: NPS (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &571598369 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571598368} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &571598370 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 571598368} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &589665224 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 589665225} + - component: {fileID: 589665227} + - component: {fileID: 589665226} + m_Layer: 5 + m_Name: Image Title (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &589665225 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 669360967} + m_Father: {fileID: 1176522086} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -52.369, y: -399} + m_SizeDelta: {x: -104.74, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &589665226 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &589665227 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 589665224} + m_CullTransparentMesh: 1 +--- !u!1 &651460150 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 651460153} + - component: {fileID: 651460152} + - component: {fileID: 651460151} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &651460151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &651460152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &651460153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &669360966 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 669360967} + - component: {fileID: 669360969} + - component: {fileID: 669360968} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &669360967 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 589665225} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &669360968 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title +--- !u!222 &669360969 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 669360966} + m_CullTransparentMesh: 1 +--- !u!1 &694584905 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 694584906} + - component: {fileID: 694584908} + - component: {fileID: 694584907} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &694584906 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1200597393} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &694584907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 69c30291565a1407abc7ca25da395ea9, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &694584908 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 694584905} + m_CullTransparentMesh: 1 +--- !u!1 &743308478 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 743308479} + - component: {fileID: 743308481} + - component: {fileID: 743308480} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &743308479 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 177909553} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &743308480 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Go ! +--- !u!222 &743308481 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 743308478} + m_CullTransparentMesh: 1 +--- !u!1 &866712465 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 866712466} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &866712466 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 866712465} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1444013441} + - {fileID: 571598369} + - {fileID: 390222344} + - {fileID: 1442321499} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &898306491 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 898306492} + - component: {fileID: 898306494} + - component: {fileID: 898306493} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &898306492 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1200597393} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &898306493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: R +--- !u!222 &898306494 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898306491} + m_CullTransparentMesh: 1 +--- !u!1 &1027181964 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1027181965} + - component: {fileID: 1027181968} + - component: {fileID: 1027181967} + - component: {fileID: 1027181966} + m_Layer: 5 + m_Name: Button Colour + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1027181965 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1347574005} + - {fileID: 1302055873} + m_Father: {fileID: 1487444786} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -447, y: -183} + m_SizeDelta: {x: 250, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1027181966 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1027181967} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1027181967 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1027181968 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027181964} + m_CullTransparentMesh: 1 +--- !u!1 &1176522085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1176522086} + - component: {fileID: 1176522088} + - component: {fileID: 1176522087} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1176522086 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 12937796} + - {fileID: 1605805618} + - {fileID: 1350751291} + - {fileID: 1526182834} + - {fileID: 82285612} + - {fileID: 589665225} + - {fileID: 1455489536} + m_Father: {fileID: 1487444786} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -100, y: 0} + m_SizeDelta: {x: 600, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1176522087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1176522088 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1176522085} + m_CullTransparentMesh: 1 +--- !u!1 &1200597392 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1200597393} + - component: {fileID: 1200597396} + - component: {fileID: 1200597395} + - component: {fileID: 1200597394} + m_Layer: 5 + m_Name: Button Colour Reset + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1200597393 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 898306492} + - {fileID: 694584906} + m_Father: {fileID: 1487444786} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -334, y: -183.00003} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1200597394 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1200597395} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1200597395 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1200597396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1200597392} + m_CullTransparentMesh: 1 +--- !u!1 &1302055872 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1302055873} + - component: {fileID: 1302055875} + - component: {fileID: 1302055874} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1302055873 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027181965} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0, y: 0.5} +--- !u!114 &1302055874 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 13ba34da9011744c884f459ce4699444, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1302055875 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1302055872} + m_CullTransparentMesh: 1 +--- !u!1 &1347574004 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1347574005} + - component: {fileID: 1347574007} + - component: {fileID: 1347574006} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1347574005 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027181965} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0.000030517578, y: 0} + m_SizeDelta: {x: 137.1865, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1347574006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Colour +--- !u!222 &1347574007 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1347574004} + m_CullTransparentMesh: 1 +--- !u!1 &1350751290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1350751291} + - component: {fileID: 1350751293} + - component: {fileID: 1350751292} + m_Layer: 5 + m_Name: Text Speed + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1350751291 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 137} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1350751292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Speed: 5' +--- !u!222 &1350751293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1350751290} + m_CullTransparentMesh: 1 +--- !u!1 &1442321498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1442321499} + - component: {fileID: 1442321500} + m_Layer: 0 + m_Name: NPS (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1442321499 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442321498} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1442321500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1442321498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1444013440 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1444013441} + - component: {fileID: 1444013442} + m_Layer: 0 + m_Name: NPS (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1444013441 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1444013440} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: 5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 866712466} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1444013442 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1444013440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1448196615 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1448196619} + - component: {fileID: 1448196618} + - component: {fileID: 1448196617} + - component: {fileID: 1448196616} + m_Layer: 0 + m_Name: Floor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!64 &1448196616 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1448196617 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5d4646112e9b746a9b531366427f3218, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1448196618 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1448196619 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1448196615} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: -1, z: 0} + m_LocalScale: {x: 15, y: 1, z: 15} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1455489535 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1455489536} + - component: {fileID: 1455489539} + - component: {fileID: 1455489538} + - component: {fileID: 1455489537} + m_Layer: 5 + m_Name: InputField (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1455489536 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 337018482} + - {fileID: 121663635} + m_Father: {fileID: 1176522086} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: -290} + m_SizeDelta: {x: 0, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1455489537 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1455489538} + m_TextComponent: {fileID: 121663636} + m_Placeholder: {fileID: 337018483} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1455489538 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1455489539 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1455489535} + m_CullTransparentMesh: 1 +--- !u!1 &1487444781 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1487444786} + - component: {fileID: 1487444785} + - component: {fileID: 1487444784} + - component: {fileID: 1487444783} + - component: {fileID: 1487444782} + m_Layer: 5 + m_Name: SceneCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1487444782 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f45e025c29e20480cb3d9ab86918814a, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonCharacterSelection: {fileID: 1949358291} + characterSelectionObject: {fileID: 1688373239} + sceneObjects: {fileID: 526073995} + cameraObject: {fileID: 1738721965} +--- !u!114 &1487444783 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1487444784 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 1 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1487444785 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_Enabled: 0 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1487444786 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1487444781} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1949358294} + - {fileID: 1705599351} + - {fileID: 177909553} + - {fileID: 1176522086} + - {fileID: 1027181965} + - {fileID: 1200597393} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1512997440 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1512997444} + - component: {fileID: 1512997443} + - component: {fileID: 1512997442} + - component: {fileID: 1512997441} + m_Layer: 0 + m_Name: NetworkManagerCharacterSelection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1512997441 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1512997442 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1512997443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 98c582433a349434990d734c5586d722, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1512997442} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 1 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 193462938415849019, guid: 622ba1e4799554a45a3443be2c75dace, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 3074504447143314537, guid: f574d1625ad4549bba64a6edf31b4d10, type: 3} + - {fileID: 2320049526911491159, guid: 59ffef73ea4ec43c09cd00a5135ca8f1, type: 3} + - {fileID: 9105303183089727057, guid: c9bc5d2c4dbfe45698e8df60415a0b9b, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + SpawnAsCharacter: 0 +--- !u!4 &1512997444 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1512997440} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1526182833 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1526182834} + - component: {fileID: 1526182836} + - component: {fileID: 1526182835} + m_Layer: 5 + m_Name: Text Attack + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1526182834 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 73} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1526182835 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Attack: 1' +--- !u!222 &1526182836 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1526182833} + m_CullTransparentMesh: 1 +--- !u!1 &1605805617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1605805618} + - component: {fileID: 1605805620} + - component: {fileID: 1605805619} + m_Layer: 5 + m_Name: Text Health + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1605805618 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1176522086} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 204} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1605805619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Health: 10' +--- !u!222 &1605805620 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605805617} + m_CullTransparentMesh: 1 +--- !u!1001 &1688373238 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6961198749896887833, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: sceneReferencer + value: + objectReference: {fileID: 1487444782} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.x + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.y + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.z + value: 100 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_Name + value: CharacterSelction + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 55ecb772328404c428beb4e2cf51044a, type: 3} +--- !u!1 &1688373239 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + m_PrefabInstance: {fileID: 1688373238} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1705599350 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1705599351} + - component: {fileID: 1705599354} + - component: {fileID: 1705599353} + - component: {fileID: 1705599352} + m_Layer: 5 + m_Name: Button Next Character + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1705599351 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 556161875} + m_Father: {fileID: 1487444786} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!114 &1705599352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1705599353} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1705599353 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1705599354 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1705599350} + m_CullTransparentMesh: 1 +--- !u!1 &1732781856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1732781857} + - component: {fileID: 1732781859} + - component: {fileID: 1732781858} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1732781857 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 12937796} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1732781858 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title +--- !u!222 &1732781859 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1732781856} + m_CullTransparentMesh: 1 +--- !u!1 &1738721965 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1738721968} + - component: {fileID: 1738721967} + - component: {fileID: 1738721966} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1738721966 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_Enabled: 1 +--- !u!20 &1738721967 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.5, g: 0.5, b: 0.5, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1738721968 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1738721965} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 526073996} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1828506693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1828506694} + - component: {fileID: 1828506696} + - component: {fileID: 1828506695} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1828506694 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1949358294} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1828506695 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X +--- !u!222 &1828506696 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1828506693} + m_CullTransparentMesh: 1 +--- !u!1 &1949358290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1949358294} + - component: {fileID: 1949358293} + - component: {fileID: 1949358292} + - component: {fileID: 1949358291} + m_Layer: 5 + m_Name: Button Character Selection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1949358291 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1949358292} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1949358292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1949358293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_CullTransparentMesh: 1 +--- !u!224 &1949358294 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1949358290} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1828506694} + - {fileID: 387810210} + m_Father: {fileID: 1487444786} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 200} + m_Pivot: {x: 1, y: 1} +--- !u!1001 &3266697494893471161 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.x + value: -3.694591 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.44966963 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.z + value: 2.4900506 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766767, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_Name + value: CharacterData + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6acf49d76d0eb47c08e908da71d52859, type: 3} diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity.meta b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity.meta new file mode 100644 index 0000000..2ef2004 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a8a73128beb4248aca152ab0364c5abc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionNoCharacter.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity new file mode 100644 index 0000000..1cf59e5 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity @@ -0,0 +1,332 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &651460150 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 651460153} + - component: {fileID: 651460152} + - component: {fileID: 651460151} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &651460151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &651460152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &651460153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 651460150} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &3266697494893471161 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.x + value: -3.694591 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.44966963 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalPosition.z + value: 2.4900506 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766753, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766767, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_Name + value: CharacterData + objectReference: {fileID: 0} + - target: {fileID: 3266697494358766767, guid: 6acf49d76d0eb47c08e908da71d52859, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 6acf49d76d0eb47c08e908da71d52859, type: 3} +--- !u!1001 &6961198749779743549 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054968, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6961198751468054969, guid: 55ecb772328404c428beb4e2cf51044a, + type: 3} + propertyPath: m_Name + value: CharacterSelection + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 55ecb772328404c428beb4e2cf51044a, type: 3} diff --git a/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity.meta b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity.meta new file mode 100644 index 0000000..48d4a0a --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7d4f83306961f4c03ab43038a1801ab2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/MirrorCharacterSelectionPreScene.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs.meta new file mode 100644 index 0000000..bac2510 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b5f08668635647cc89fb5576796a26a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab new file mode 100644 index 0000000..9230a04 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3266697494358766767 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3266697494358766753} + - component: {fileID: 3266697494358766766} + m_Layer: 0 + m_Name: CharacterData + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3266697494358766753 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3266697494358766767} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.694591, y: 0.44966963, z: 2.4900506} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3266697494358766766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3266697494358766767} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f5fc49087bdc848b2aefe5c91858c7b1, type: 3} + m_Name: + m_EditorClassIdentifier: + characterPrefabs: + - {fileID: 0} + - {fileID: 9105303183089727057, guid: c9bc5d2c4dbfe45698e8df60415a0b9b, type: 3} + - {fileID: 2320049526911491159, guid: 59ffef73ea4ec43c09cd00a5135ca8f1, type: 3} + - {fileID: 3074504447143314537, guid: f574d1625ad4549bba64a6edf31b4d10, type: 3} + characterTitles: + - + - Medic + - Heavy + - Assault + characterHealths: 000000000a000000140000000f000000 + characterSpeeds: + - 0 + - 5 + - 1 + - 3 + characterAttack: 00000000010000000300000002000000 + characterAbilities: + - + - Health Regen, Medipack + - Bazooka, Armour absorb first hit + - Infinite Pistol Ammo diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab.meta new file mode 100644 index 0000000..88f308d --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 6acf49d76d0eb47c08e908da71d52859 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterData.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab new file mode 100644 index 0000000..9f94e42 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab @@ -0,0 +1,2696 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6961198749817030820 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198749817030823} + - component: {fileID: 6961198749817030817} + - component: {fileID: 6961198749817030822} + m_Layer: 5 + m_Name: Image Title (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &6961198749817030823 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749817030820} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750980167100} + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -52.369, y: -399} + m_SizeDelta: {x: -104.74, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198749817030817 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749817030820} + m_CullTransparentMesh: 1 +--- !u!114 &6961198749817030822 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749817030820} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6961198749896887842 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198749896887838} + - component: {fileID: 6961198749896887839} + - component: {fileID: 6961198749896887836} + - component: {fileID: 6961198749896887837} + - component: {fileID: 6961198749896887833} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198749896887838 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749896887842} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 6961198750746120044} + - {fileID: 6961198751653829985} + - {fileID: 6961198751546360194} + - {fileID: 6961198750187510689} + - {fileID: 6961198750253286744} + - {fileID: 6961198751358499530} + m_Father: {fileID: 6961198751468054968} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &6961198749896887839 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749896887842} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &6961198749896887836 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749896887842} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 1 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &6961198749896887837 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749896887842} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &6961198749896887833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749896887842} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: faef105eb77a94bbaacfe57f48968e19, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonExit: {fileID: 6961198750746120047} + buttonNextCharacter: {fileID: 6961198751653829984} + buttonGo: {fileID: 6961198751546360317} + buttonColour: {fileID: 6961198750253286751} + buttonColourReset: {fileID: 6961198751358499529} + textTitle: {fileID: 6961198751814796713} + textHealth: {fileID: 6961198750152554927} + textSpeed: {fileID: 6961198751795177450} + textAttack: {fileID: 6961198750096000043} + textAbilities: {fileID: 6961198751744583697} + inputFieldPlayerName: {fileID: 6961198751004169283} + podiumPosition: {fileID: 6961198750704402548} + sceneReferencer: {fileID: 0} + cameraObj: {fileID: 6961198751400663442} +--- !u!1 &6961198749922865296 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198749922865298} + - component: {fileID: 6961198749922865299} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198749922865298 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749922865296} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751468054968} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!108 &6961198749922865299 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749922865296} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!1 &6961198749955512856 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198749955512859} + - component: {fileID: 6961198749955512853} + - component: {fileID: 6961198749955512858} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198749955512859 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749955512856} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751546360194} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198749955512853 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749955512856} + m_CullTransparentMesh: 1 +--- !u!114 &6961198749955512858 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198749955512856} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Go ! +--- !u!1 &6961198750096000041 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750096000040} + - component: {fileID: 6961198750096000042} + - component: {fileID: 6961198750096000043} + m_Layer: 5 + m_Name: Text Attack + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750096000040 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750096000041} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 73} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750096000042 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750096000041} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750096000043 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750096000041} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Attack: 1' +--- !u!1 &6961198750152554925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750152554924} + - component: {fileID: 6961198750152554926} + - component: {fileID: 6961198750152554927} + m_Layer: 5 + m_Name: Text Health + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750152554924 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750152554925} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 204} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750152554926 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750152554925} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750152554927 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750152554925} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Health: 10' +--- !u!1 &6961198750187510694 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750187510689} + - component: {fileID: 6961198750187510691} + - component: {fileID: 6961198750187510688} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750187510689 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750187510694} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750429780790} + - {fileID: 6961198750152554924} + - {fileID: 6961198751795177451} + - {fileID: 6961198750096000040} + - {fileID: 6961198751744583702} + - {fileID: 6961198749817030823} + - {fileID: 6961198751004169280} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -100, y: 0} + m_SizeDelta: {x: 600, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &6961198750187510691 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750187510694} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750187510688 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750187510694} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6961198750248404073 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750248404072} + - component: {fileID: 6961198750248404074} + - component: {fileID: 6961198750248404075} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750248404072 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750248404073} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751004169280} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750248404074 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750248404073} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750248404075 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750248404073} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.5} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter player name... +--- !u!1 &6961198750253286748 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750253286744} + - component: {fileID: 6961198750253286745} + - component: {fileID: 6961198750253286750} + - component: {fileID: 6961198750253286751} + m_Layer: 5 + m_Name: Button Colour + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750253286744 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750253286748} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750282644101} + - {fileID: 6961198751002574813} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -447, y: -183} + m_SizeDelta: {x: 250, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &6961198750253286745 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750253286748} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750253286750 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750253286748} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198750253286751 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750253286748} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198750253286750} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6961198750282644106 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750282644101} + - component: {fileID: 6961198750282644103} + - component: {fileID: 6961198750282644100} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750282644101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750282644106} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750253286744} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0.000030517578, y: 0} + m_SizeDelta: {x: 137.1865, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &6961198750282644103 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750282644106} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750282644100 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750282644106} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Colour +--- !u!1 &6961198750429780791 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750429780790} + - component: {fileID: 6961198750429780784} + - component: {fileID: 6961198750429780785} + m_Layer: 5 + m_Name: Image Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750429780790 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750429780791} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198751814796718} + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 290} + m_SizeDelta: {x: 0.000022074748, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750429780784 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750429780791} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750429780785 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750429780791} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 0.2509804} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6961198750566825764 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750566825767} + - component: {fileID: 6961198750566825761} + - component: {fileID: 6961198750566825766} + m_Layer: 0 + m_Name: PodiumBase + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198750566825767 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750566825764} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -0.05399996, z: 0} + m_LocalScale: {x: 1, y: 0.04572, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751593960330} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &6961198750566825761 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750566825764} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6961198750566825766 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750566825764} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0eb01134dad314f879704d594ca8a7b2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &6961198750587464270 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750587464265} + - component: {fileID: 6961198750587464267} + - component: {fileID: 6961198750587464264} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750587464265 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750587464270} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751358499530} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750587464267 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750587464270} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750587464264 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750587464270} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 69c30291565a1407abc7ca25da395ea9, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6961198750704402549 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750704402548} + m_Layer: 0 + m_Name: CharacterPodiumPosition + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198750704402548 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750704402549} + m_LocalRotation: {x: 0, y: 0.9063079, z: 0, w: 0.42261827} + m_LocalPosition: {x: 0, y: 0.1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751593960330} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 130, z: 0} +--- !u!1 &6961198750746120045 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750746120044} + - component: {fileID: 6961198750746120041} + - component: {fileID: 6961198750746120046} + - component: {fileID: 6961198750746120047} + m_Layer: 5 + m_Name: Button Exit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750746120044 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750746120045} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198751231886820} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 1} +--- !u!222 &6961198750746120041 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750746120045} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750746120046 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750746120045} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198750746120047 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750746120045} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198750746120046} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6961198750812491072 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750812491075} + - component: {fileID: 6961198750812491197} + - component: {fileID: 6961198750812491074} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750812491075 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750812491072} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751004169280} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750812491197 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750812491072} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750812491074 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750812491072} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 4 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!1 &6961198750896600773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750896600772} + - component: {fileID: 6961198750896600774} + - component: {fileID: 6961198750896600775} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750896600772 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750896600773} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751653829985} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750896600774 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750896600773} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750896600775 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750896600773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 6 + m_MaxSize: 60 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: '>' +--- !u!1 &6961198750901700357 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750901700356} + - component: {fileID: 6961198750901700358} + - component: {fileID: 6961198750901700359} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &6961198750901700356 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750901700357} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751358499530} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750901700358 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750901700357} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750901700359 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750901700357} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: R +--- !u!1 &6961198750980167101 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198750980167100} + - component: {fileID: 6961198750980167102} + - component: {fileID: 6961198750980167103} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198750980167100 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750980167101} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198749817030823} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198750980167102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750980167101} + m_CullTransparentMesh: 1 +--- !u!114 &6961198750980167103 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198750980167101} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title +--- !u!1 &6961198751002574818 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751002574813} + - component: {fileID: 6961198751002574815} + - component: {fileID: 6961198751002574812} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751002574813 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751002574818} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750253286744} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 80, y: 80} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &6961198751002574815 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751002574818} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751002574812 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751002574818} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.7529412} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 13ba34da9011744c884f459ce4699444, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6961198751004169281 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751004169280} + - component: {fileID: 6961198751004169405} + - component: {fileID: 6961198751004169282} + - component: {fileID: 6961198751004169283} + m_Layer: 5 + m_Name: InputField (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751004169280 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751004169281} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750248404072} + - {fileID: 6961198750812491075} + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: -290} + m_SizeDelta: {x: 0, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198751004169405 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751004169281} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751004169282 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751004169281} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198751004169283 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751004169281} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198751004169282} + m_TextComponent: {fileID: 6961198750812491074} + m_Placeholder: {fileID: 6961198750248404075} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!1 &6961198751231886821 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751231886820} + - component: {fileID: 6961198751231886822} + - component: {fileID: 6961198751231886823} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751231886820 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751231886821} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750746120044} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198751231886822 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751231886821} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751231886823 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751231886821} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X +--- !u!1 &6961198751358499534 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751358499530} + - component: {fileID: 6961198751358499531} + - component: {fileID: 6961198751358499528} + - component: {fileID: 6961198751358499529} + m_Layer: 5 + m_Name: Button Colour Reset + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751358499530 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751358499534} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750901700356} + - {fileID: 6961198750587464265} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -334, y: -183.00003} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &6961198751358499531 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751358499534} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751358499528 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751358499534} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198751358499529 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751358499534} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198751358499528} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6961198751400663440 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751400663437} + - component: {fileID: 6961198751400663442} + - component: {fileID: 6961198751400663443} + m_Layer: 0 + m_Name: Main Camera + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198751400663437 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751400663440} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198751468054968} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!20 &6961198751400663442 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751400663440} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.2735849, g: 0.2735849, b: 0.2735849, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 20 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!81 &6961198751400663443 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751400663440} + m_Enabled: 1 +--- !u!1 &6961198751468054969 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751468054968} + m_Layer: 0 + m_Name: CharacterSelection + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198751468054968 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751468054969} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198751400663437} + - {fileID: 6961198749922865298} + - {fileID: 6961198751593960330} + - {fileID: 6961198749896887838} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6961198751537308133 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751537308132} + - component: {fileID: 6961198751537308134} + - component: {fileID: 6961198751537308135} + m_Layer: 0 + m_Name: PodiumTop + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198751537308132 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751537308133} + m_LocalRotation: {x: 0, y: 0.9063079, z: 0, w: 0.42261827} + m_LocalPosition: {x: 0, y: -0.004, z: 0} + m_LocalScale: {x: 1.0001, y: 0.0001, z: 1.0001} + m_Children: [] + m_Father: {fileID: 6961198751593960330} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 130, z: 0} +--- !u!33 &6961198751537308134 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751537308133} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6961198751537308135 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751537308133} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 8571b3e10d2fa4348b4df0dbdc082c32, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &6961198751546360195 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751546360194} + - component: {fileID: 6961198751546360319} + - component: {fileID: 6961198751546360316} + - component: {fileID: 6961198751546360317} + m_Layer: 5 + m_Name: Button Go + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751546360194 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751546360195} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198749955512859} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -0.00012207031, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 1, y: 0} +--- !u!222 &6961198751546360319 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751546360195} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751546360316 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751546360195} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.1254902, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198751546360317 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751546360195} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198751546360316} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6961198751593960331 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751593960330} + m_Layer: 0 + m_Name: PodiumHolder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6961198751593960330 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751593960331} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -1, y: -1, z: 2.6} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750566825767} + - {fileID: 6961198751537308132} + - {fileID: 6961198750704402548} + m_Father: {fileID: 6961198751468054968} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6961198751653829990 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751653829985} + - component: {fileID: 6961198751653829986} + - component: {fileID: 6961198751653829987} + - component: {fileID: 6961198751653829984} + m_Layer: 5 + m_Name: Button Next Character + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751653829985 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751653829990} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6961198750896600772} + m_Father: {fileID: 6961198749896887838} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 680} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &6961198751653829986 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751653829990} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751653829987 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751653829990} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.1254902, g: 0.1254902, b: 0.007843138, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6961198751653829984 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751653829990} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6961198751653829987} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6961198751744583703 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751744583702} + - component: {fileID: 6961198751744583696} + - component: {fileID: 6961198751744583697} + m_Layer: 5 + m_Name: Text Abilities + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751744583702 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751744583703} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: -41.62291} + m_SizeDelta: {x: 512.3848, y: 158.2005} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198751744583696 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751744583703} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751744583697 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751744583703} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Abilities: + + Likes to party' +--- !u!1 &6961198751795177448 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751795177451} + - component: {fileID: 6961198751795177445} + - component: {fileID: 6961198751795177450} + m_Layer: 5 + m_Name: Text Speed + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751795177451 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751795177448} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750187510689} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.8201904, y: 137} + m_SizeDelta: {x: 581.5911, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198751795177445 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751795177448} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751795177450 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751795177448} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 40 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Speed: 5' +--- !u!1 &6961198751814796719 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6961198751814796718} + - component: {fileID: 6961198751814796712} + - component: {fileID: 6961198751814796713} + m_Layer: 5 + m_Name: Text Title + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6961198751814796718 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751814796719} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 6961198750429780790} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 710, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6961198751814796712 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751814796719} + m_CullTransparentMesh: 1 +--- !u!114 &6961198751814796713 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6961198751814796719} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 60 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Title diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab.meta new file mode 100644 index 0000000..ecbfcd7 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 55ecb772328404c428beb4e2cf51044a +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/CharacterSelection.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters.meta new file mode 100644 index 0000000..5a0509f --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5148755e596054c719374dddb8ced598 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab new file mode 100644 index 0000000..38ea6da --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab @@ -0,0 +1,1961 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1426017861 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1426017862} + m_Layer: 0 + m_Name: FloatingInfo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1426017862 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1426017861} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 2.15, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1898764922} + m_Father: {fileID: 3074504447143314538} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1898764921 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1898764922} + - component: {fileID: 1898764924} + - component: {fileID: 1898764923} + m_Layer: 0 + m_Name: CharacterName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1898764922 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1898764921} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.02, y: 0.02, z: 0.02} + m_Children: [] + m_Father: {fileID: 1426017862} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1898764924 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1898764921} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &1898764923 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1898764921} + m_Text: Player Name + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 7 + m_Alignment: 1 + m_TabSize: 4 + m_FontSize: 100 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_Color: + serializedVersion: 2 + rgba: 3238002687 +--- !u!1 &3074504445674343831 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445674343824} + - component: {fileID: 3074504445674343826} + - component: {fileID: 3074504445674343825} + m_Layer: 0 + m_Name: Arm + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445674343824 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445674343831} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.366, y: 0.88899994, z: -0.03} + m_LocalScale: {x: 0.07982323, y: 0.22659165, z: 0.6414468} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &3074504445674343826 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445674343831} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445674343825 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445674343831} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504445720021772 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445720021773} + - component: {fileID: 3074504445720021775} + - component: {fileID: 3074504445720021774} + m_Layer: 0 + m_Name: Hat (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445720021773 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445720021772} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.617, z: 0} + m_LocalScale: {x: 0.39611518, y: 0.113032, z: 0.40592375} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3074504445720021775 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445720021772} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445720021774 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445720021772} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504445742208680 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445742208681} + - component: {fileID: 3074504445742208683} + - component: {fileID: 3074504445742208682} + m_Layer: 0 + m_Name: Ammo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445742208681 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445742208680} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.2225, y: 0.834, z: 0.2372} + m_LocalScale: {x: 0.012793455, y: 0.12303568, z: 0.061496694} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 16 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504445742208683 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445742208680} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445742208682 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445742208680} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504445760471456 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445760471457} + - component: {fileID: 3074504445760471459} + - component: {fileID: 3074504445760471458} + m_Layer: 0 + m_Name: Arm + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445760471457 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445760471456} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: -0.36, y: 0.88899994, z: -0.03} + m_LocalScale: {x: 0.07982323, y: 0.22659165, z: 0.6414468} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 13 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &3074504445760471459 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445760471456} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445760471458 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445760471456} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504445765275294 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445765275295} + - component: {fileID: 3074504445765275289} + - component: {fileID: 3074504445765275288} + m_Layer: 0 + m_Name: Shoulder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445765275295 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445765275294} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.008, y: 1.0359999, z: -0.03} + m_LocalScale: {x: 0.66056913, y: 0.22659165, z: 0.44993904} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 12 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &3074504445765275289 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445765275294} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445765275288 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445765275294} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504445848950743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504445848950736} + - component: {fileID: 3074504445848950738} + - component: {fileID: 3074504445848950737} + m_Layer: 0 + m_Name: Leg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504445848950736 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445848950743} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: -0.167, y: 0.52099997, z: -0.005} + m_LocalScale: {x: 0.27052116, y: 0.6216682, z: 0.21178184} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504445848950738 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445848950743} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504445848950737 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504445848950743} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446040140512 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446040140513} + - component: {fileID: 3074504446040140515} + - component: {fileID: 3074504446040140514} + m_Layer: 0 + m_Name: Nose + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446040140513 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446040140512} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.003, y: 1.2149999, z: 0.225} + m_LocalScale: {x: 0.052220587, y: 0.052909207, z: 0.19615689} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &3074504446040140515 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446040140512} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446040140514 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446040140512} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446114063250 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446114063251} + - component: {fileID: 3074504446114063245} + - component: {fileID: 3074504446114063244} + m_Layer: 0 + m_Name: Tache + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446114063251 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446114063250} + m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: -0.5} + m_LocalPosition: {x: 0.003, y: 1.1439999, z: 0.238} + m_LocalScale: {x: 0.052220576, y: 0.052909195, z: 0.19615684} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 90} +--- !u!33 &3074504446114063245 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446114063250} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446114063244 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446114063250} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446142477691 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446142477684} + - component: {fileID: 3074504446142477686} + - component: {fileID: 3074504446142477685} + m_Layer: 0 + m_Name: Body + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446142477684 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446142477691} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.1209999, z: 0} + m_LocalScale: {x: 0.45, y: 0.65646, z: 0.45} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3074504446142477686 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446142477691} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446142477685 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446142477691} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6a1d409bf7eea44168084517c7ee81cf, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446213947200 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446213947201} + - component: {fileID: 3074504446213947203} + - component: {fileID: 3074504446213947202} + m_Layer: 0 + m_Name: Foot + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446213947201 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446213947200} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: -0.168, y: 0.11099994, z: 0.048} + m_LocalScale: {x: 0.43514544, y: 0.18316153, z: 0.27675515} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446213947203 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446213947200} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446213947202 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446213947200} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446469250251 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446469250244} + - component: {fileID: 3074504446469250246} + - component: {fileID: 3074504446469250245} + m_Layer: 0 + m_Name: Chest (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446469250244 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446469250251} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 0.8989999, z: 0.016} + m_LocalScale: {x: 0.43514544, y: 0.30545047, z: 0.53939205} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 15 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446469250246 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446469250251} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446469250245 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446469250251} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446528525125 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446528525126} + - component: {fileID: 3074504446528525120} + - component: {fileID: 3074504446528525127} + m_Layer: 0 + m_Name: Ammo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446528525126 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446528525125} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.1381, y: 0.834, z: 0.2372} + m_LocalScale: {x: 0.012793455, y: 0.12303568, z: 0.061496694} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 17 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446528525120 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446528525125} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446528525127 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446528525125} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446812613656 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446812613657} + - component: {fileID: 3074504446812613659} + - component: {fileID: 3074504446812613658} + m_Layer: 0 + m_Name: Foot + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446812613657 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446812613656} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.16499993, y: 0.11099994, z: 0.047999993} + m_LocalScale: {x: 0.43514544, y: 0.18316153, z: 0.27675515} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446812613659 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446812613656} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446812613658 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446812613656} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446862473654 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446862473655} + - component: {fileID: 3074504446862473649} + - component: {fileID: 3074504446862473648} + m_Layer: 0 + m_Name: Ammo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446862473655 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446862473654} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.0563, y: 0.834, z: 0.2372} + m_LocalScale: {x: 0.012793455, y: 0.12303568, z: 0.061496694} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 18 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446862473649 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446862473654} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446862473648 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446862473654} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504446994015446 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504446994015447} + - component: {fileID: 3074504446994015441} + - component: {fileID: 3074504446994015440} + m_Layer: 0 + m_Name: Belt + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504446994015447 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446994015446} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 0.71999997, z: -0.005} + m_LocalScale: {x: 0.5212124, y: 0.12303568, z: 0.5694776} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504446994015441 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446994015446} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504446994015440 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504446994015446} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504447096303301 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504447096303302} + - component: {fileID: 3074504447096303296} + - component: {fileID: 3074504447096303303} + m_Layer: 0 + m_Name: Chest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504447096303302 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447096303301} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 0.987, z: -0.036} + m_LocalScale: {x: 0.43514544, y: 0.6216682, z: 0.53939205} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504447096303296 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447096303301} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504447096303303 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447096303301} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504447143314537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504447143314538} + - component: {fileID: 108717044788610704} + - component: {fileID: 7793988651217454999} + - component: {fileID: 7573674391122441047} + - component: {fileID: 751312970937383153} + - component: {fileID: -5286820321314269966} + - component: {fileID: -7583946280607460006} + - component: {fileID: -6913491101915066918} + - component: {fileID: 5149898387657116502} + m_Layer: 0 + m_Name: CharacterAssault + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504447143314538 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3482650701086459826} + - {fileID: 1426017862} + - {fileID: 8318204445083151948} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &108717044788610704 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e04a8cb02afdc4e778925020d233d718, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + floatingInfo: {fileID: 1426017862} + characterNumber: 0 + textMeshName: {fileID: 1898764923} + playerName: + characterColour: {r: 0, g: 0, b: 0, a: 0} + characterRenderers: + - {fileID: 3074504447607218934} + - {fileID: 3074504445674343825} + - {fileID: 3074504447096303303} + - {fileID: 3074504445720021774} + - {fileID: 3074504447387526168} + - {fileID: 3074504445760471458} + - {fileID: 3074504446469250245} + - {fileID: 3074504445848950737} +--- !u!54 &7793988651217454999 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!136 &7573674391122441047 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 1, z: 0} +--- !u!143 &751312970937383153 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 1, z: 0} +--- !u!114 &-5286820321314269966 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 161514985 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-7583946280607460006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 3074504447143314538} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-6913491101915066918 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f81b59082839c2e40938767457bb91ae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 751312970937383153} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!114 &5149898387657116502 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447143314537} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db9418a9e709a7844acac42de096cba6, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterSelection: {fileID: 108717044788610704} + cameraTarget: {fileID: 8318204445083151948} + sceneReferencer: {fileID: 0} + cameraObj: {fileID: 0} +--- !u!1 &3074504447184887503 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504447184887496} + - component: {fileID: 3074504447184887498} + - component: {fileID: 3074504447184887497} + m_Layer: 0 + m_Name: Brow + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504447184887496 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447184887503} + m_LocalRotation: {x: 0.5, y: 0.5, z: -0.5, w: -0.5} + m_LocalPosition: {x: 0.003, y: 1.336, z: 0.242} + m_LocalScale: {x: 0.052220576, y: 0.052909195, z: 0.36183092} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 14 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 90} +--- !u!33 &3074504447184887498 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447184887503} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504447184887497 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447184887503} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b976126dcdf3a407b86a1488c2f05b98, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504447387526174 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504447387526175} + - component: {fileID: 3074504447387526169} + - component: {fileID: 3074504447387526168} + m_Layer: 0 + m_Name: Leg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504447387526175 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447387526174} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.165, y: 0.52099997, z: -0.005} + m_LocalScale: {x: 0.27052116, y: 0.6216682, z: 0.21178184} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &3074504447387526169 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447387526174} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504447387526168 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447387526174} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &3074504447607218932 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3074504447607218933} + - component: {fileID: 3074504447607218935} + - component: {fileID: 3074504447607218934} + m_Layer: 0 + m_Name: Hat + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3074504447607218933 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447607218932} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.517, z: 0} + m_LocalScale: {x: 0.469684, y: 0.14322086, z: 0.48131424} + m_Children: [] + m_Father: {fileID: 3482650701086459826} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3074504447607218935 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447607218932} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3074504447607218934 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3074504447607218932} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: c563271c8eff8458a9d61b9a48b9cb12, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &6475712709169132855 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3482650701086459826} + - component: {fileID: 2605689034447552395} + m_Layer: 0 + m_Name: Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3482650701086459826 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6475712709169132855} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3074504446142477684} + - {fileID: 3074504447607218933} + - {fileID: 3074504445674343824} + - {fileID: 3074504447096303302} + - {fileID: 3074504446812613657} + - {fileID: 3074504446213947201} + - {fileID: 3074504445720021773} + - {fileID: 3074504447387526175} + - {fileID: 3074504446994015447} + - {fileID: 3074504445848950736} + - {fileID: 3074504446040140513} + - {fileID: 3074504446114063251} + - {fileID: 3074504445765275295} + - {fileID: 3074504445760471457} + - {fileID: 3074504447184887496} + - {fileID: 3074504446469250244} + - {fileID: 3074504445742208681} + - {fileID: 3074504446528525126} + - {fileID: 3074504446862473655} + m_Father: {fileID: 3074504447143314538} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2605689034447552395 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6475712709169132855} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0f36e96df6ff2459992432717c975c84, type: 3} + m_Name: + m_EditorClassIdentifier: + minimum: 0 + maximum: 0.25 + bounceSpeed: 2.5 +--- !u!1 &7963974170956753149 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8318204445083151948} + m_Layer: 0 + m_Name: CameraTarget + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8318204445083151948 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7963974170956753149} + m_LocalRotation: {x: 0.08715578, y: 0, z: 0, w: 0.9961947} + m_LocalPosition: {x: 0, y: 2, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3074504447143314538} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab.meta new file mode 100644 index 0000000..e1bcf77 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f574d1625ad4549bba64a6edf31b4d10 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterAssault.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab new file mode 100644 index 0000000..11c92b0 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab @@ -0,0 +1,1478 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &629208452007675340 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7040283211484466521} + m_Layer: 0 + m_Name: FloatingInfo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7040283211484466521 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 629208452007675340} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 2.15, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3577432386190868119} + m_Father: {fileID: 2320049526911491158} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1151154662640058319 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7343421379812896117} + - component: {fileID: 2521015910530906823} + m_Layer: 0 + m_Name: Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7343421379812896117 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1151154662640058319} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2320049527835465562} + - {fileID: 2320049527547486268} + - {fileID: 2320049528186941541} + - {fileID: 2320049526338229879} + - {fileID: 2320049526591366755} + - {fileID: 2320049527900410496} + - {fileID: 2320049526879068636} + - {fileID: 2320049527168386025} + - {fileID: 2320049527593028057} + - {fileID: 2320049528211028348} + - {fileID: 2320049527223728705} + - {fileID: 2320049527632197637} + - {fileID: 2320049527909226428} + m_Father: {fileID: 2320049526911491158} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2521015910530906823 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1151154662640058319} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0f36e96df6ff2459992432717c975c84, type: 3} + m_Name: + m_EditorClassIdentifier: + minimum: 0 + maximum: 0.25 + bounceSpeed: 2 +--- !u!1 &2320049526338229880 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049526338229879} + - component: {fileID: 2320049526338229877} + - component: {fileID: 2320049526338229878} + m_Layer: 0 + m_Name: Accessory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049526338229879 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526338229880} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.31499988, y: 1.043, z: 0} + m_LocalScale: {x: 0.034146547, y: 0.16708128, z: 0.066153266} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &2320049526338229877 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526338229880} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049526338229878 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526338229880} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4501a33f89e954d2aacce3ee73c43903, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049526591366756 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049526591366755} + - component: {fileID: 2320049526591366753} + - component: {fileID: 2320049526591366754} + m_Layer: 0 + m_Name: Chest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049526591366755 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526591366756} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 0.83000004, z: 0} + m_LocalScale: {x: 0.43514544, y: 0.6216682, z: 0.60778624} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049526591366753 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526591366756} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049526591366754 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526591366756} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b4814d6b577aa424991905946c0fe6dc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049526879068637 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049526879068636} + - component: {fileID: 2320049526879068634} + - component: {fileID: 2320049526879068635} + m_Layer: 0 + m_Name: Leg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049526879068636 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526879068637} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.165, y: 0.171, z: 0} + m_LocalScale: {x: 0.43514544, y: 0.31963688, z: 0.27675515} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049526879068634 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526879068637} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049526879068635 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526879068637} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b4814d6b577aa424991905946c0fe6dc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049526911491159 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049526911491158} + - component: {fileID: 597190161414468650} + - component: {fileID: -7557158431007955717} + - component: {fileID: -1015958069242222231} + - component: {fileID: -2971273460793977018} + - component: {fileID: 986579869238452304} + - component: {fileID: 3123254521016284903} + - component: {fileID: 6959445442754512381} + - component: {fileID: -4217278923851902145} + m_Layer: 0 + m_Name: CharacterHeavy + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049526911491158 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7343421379812896117} + - {fileID: 7040283211484466521} + - {fileID: 5721588646566991880} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &597190161414468650 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e04a8cb02afdc4e778925020d233d718, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + floatingInfo: {fileID: 7040283211484466521} + characterNumber: 0 + textMeshName: {fileID: 408287653024585617} + playerName: + characterColour: {r: 0, g: 0, b: 0, a: 0} + characterRenderers: + - {fileID: 2320049528186941540} + - {fileID: 2320049526591366754} + - {fileID: 2320049527593028056} + - {fileID: 2320049526879068635} + - {fileID: 2320049528211028347} +--- !u!54 &-7557158431007955717 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!136 &-1015958069242222231 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 1 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!143 &-2971273460793977018 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &986579869238452304 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3014732734 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3123254521016284903 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 2320049526911491158} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &6959445442754512381 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f81b59082839c2e40938767457bb91ae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: -2971273460793977018} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!114 &-4217278923851902145 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049526911491159} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db9418a9e709a7844acac42de096cba6, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterSelection: {fileID: 597190161414468650} + cameraTarget: {fileID: 5721588646566991880} + sceneReferencer: {fileID: 0} + cameraObj: {fileID: 0} +--- !u!1 &2320049527168386026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527168386025} + - component: {fileID: 2320049527168386023} + - component: {fileID: 2320049527168386024} + m_Layer: 0 + m_Name: Accessory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527168386025 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527168386026} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.315, y: 0.941, z: 0} + m_LocalScale: {x: 0.034146547, y: 0.16708128, z: 0.066153266} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &2320049527168386023 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527168386026} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527168386024 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527168386026} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4501a33f89e954d2aacce3ee73c43903, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527223728706 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527223728705} + - component: {fileID: 2320049527223728735} + - component: {fileID: 2320049527223728704} + m_Layer: 0 + m_Name: Bag (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527223728705 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527223728706} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.187, y: 0.90999997, z: -0.401} + m_LocalScale: {x: 0.10340634, y: 0.7512555, z: 0.10445774} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049527223728735 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527223728706} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527223728704 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527223728706} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0f0dbf645ce2a45b390c0514e3758988, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527547486269 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527547486268} + - component: {fileID: 2320049527547486266} + - component: {fileID: 2320049527547486267} + m_Layer: 0 + m_Name: Accessory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527547486268 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527547486269} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: -0.5} + m_LocalPosition: {x: 0, y: 1.588, z: 0.22600007} + m_LocalScale: {x: 0.034146544, y: 0.16708137, z: 0.06615327} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &2320049527547486266 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527547486269} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527547486267 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527547486269} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4501a33f89e954d2aacce3ee73c43903, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527593028058 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527593028057} + - component: {fileID: 2320049527593028055} + - component: {fileID: 2320049527593028056} + m_Layer: 0 + m_Name: Leg + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527593028057 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527593028058} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: -0.168, y: 0.171, z: 0} + m_LocalScale: {x: 0.43514544, y: 0.31963688, z: 0.27675515} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049527593028055 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527593028058} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527593028056 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527593028058} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b4814d6b577aa424991905946c0fe6dc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527632197638 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527632197637} + - component: {fileID: 2320049527632197635} + - component: {fileID: 2320049527632197636} + m_Layer: 0 + m_Name: Bag (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527632197637 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527632197638} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: -0.185, y: 0.90999997, z: -0.401} + m_LocalScale: {x: 0.10340634, y: 0.7512555, z: 0.10445774} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049527632197635 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527632197638} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527632197636 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527632197638} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0f0dbf645ce2a45b390c0514e3758988, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527835465563 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527835465562} + - component: {fileID: 2320049527835465560} + - component: {fileID: 2320049527835465561} + m_Layer: 0 + m_Name: Body + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527835465562 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527835465563} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 0.872, z: 0} + m_LocalScale: {x: 0.5167786, y: 1.303632, z: 0.38589802} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2320049527835465560 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527835465563} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527835465561 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527835465563} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6a1d409bf7eea44168084517c7ee81cf, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527900410497 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527900410496} + - component: {fileID: 2320049527900410526} + - component: {fileID: 2320049527900410527} + m_Layer: 0 + m_Name: Accessory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527900410496 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527900410497} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: -0.5} + m_LocalPosition: {x: 0, y: 1.4984001, z: 0.22600007} + m_LocalScale: {x: 0.034146544, y: 0.16708137, z: 0.06615327} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &2320049527900410526 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527900410497} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527900410527 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527900410497} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4501a33f89e954d2aacce3ee73c43903, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049527909226429 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049527909226428} + - component: {fileID: 2320049527909226426} + - component: {fileID: 2320049527909226427} + m_Layer: 0 + m_Name: Bag (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049527909226428 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527909226429} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.012, y: 0.90999997, z: -0.401} + m_LocalScale: {x: 0.10340634, y: 0.7512555, z: 0.10445774} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 12 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049527909226426 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527909226429} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049527909226427 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049527909226429} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0f0dbf645ce2a45b390c0514e3758988, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049528186941542 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049528186941541} + - component: {fileID: 2320049528186941539} + - component: {fileID: 2320049528186941540} + m_Layer: 0 + m_Name: Hat + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049528186941541 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528186941542} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.542, z: 0} + m_LocalScale: {x: 0.35982606, y: 0.20080449, z: 0.43514535} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &2320049528186941539 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528186941542} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049528186941540 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528186941542} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b4814d6b577aa424991905946c0fe6dc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &2320049528211028349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2320049528211028348} + - component: {fileID: 2320049528211028346} + - component: {fileID: 2320049528211028347} + m_Layer: 0 + m_Name: Bag + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2320049528211028348 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528211028349} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 0.888, z: -0.346} + m_LocalScale: {x: 0.2891522, y: 0.419392, z: 0.5326068} + m_Children: [] + m_Father: {fileID: 7343421379812896117} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &2320049528211028346 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528211028349} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2320049528211028347 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2320049528211028349} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b4814d6b577aa424991905946c0fe6dc, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5339566775090360811 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5721588646566991880} + m_Layer: 0 + m_Name: CameraTarget + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5721588646566991880 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5339566775090360811} + m_LocalRotation: {x: 0.08715578, y: 0, z: 0, w: 0.9961947} + m_LocalPosition: {x: 0, y: 2, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2320049526911491158} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0} +--- !u!1 &6134056180033061664 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3577432386190868119} + - component: {fileID: 5462666342516420674} + - component: {fileID: 408287653024585617} + m_Layer: 0 + m_Name: CharacterName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3577432386190868119 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6134056180033061664} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.02, y: 0.02, z: 0.02} + m_Children: [] + m_Father: {fileID: 7040283211484466521} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &5462666342516420674 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6134056180033061664} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &408287653024585617 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6134056180033061664} + m_Text: ste + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 7 + m_Alignment: 1 + m_TabSize: 4 + m_FontSize: 100 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_Color: + serializedVersion: 2 + rgba: 3238002687 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab.meta new file mode 100644 index 0000000..8691e27 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 59ffef73ea4ec43c09cd00a5135ca8f1 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterHeavy.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab new file mode 100644 index 0000000..ae7f27f --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab @@ -0,0 +1,1157 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &127148748194157038 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7648894086210803939} + - component: {fileID: 2768581363641972790} + m_Layer: 0 + m_Name: Model + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7648894086210803939 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 127148748194157038} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 9105303182255863692} + - {fileID: 9105303183055541653} + - {fileID: 9105303182365644252} + - {fileID: 9105303183937996604} + - {fileID: 9105303183019705936} + - {fileID: 9105303182223144759} + - {fileID: 9105303183086384158} + - {fileID: 9105303183046110717} + - {fileID: 9105303183986044558} + m_Father: {fileID: 9105303183089727062} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2768581363641972790 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 127148748194157038} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0f36e96df6ff2459992432717c975c84, type: 3} + m_Name: + m_EditorClassIdentifier: + minimum: 0 + maximum: 0.25 + bounceSpeed: 3 +--- !u!1 &575312753228297204 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5872215246660754301} + - component: {fileID: 6135228682338357176} + - component: {fileID: 3542259476824360018} + m_Layer: 0 + m_Name: CharacterName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5872215246660754301 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 575312753228297204} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.02, y: 0.02, z: 0.02} + m_Children: [] + m_Father: {fileID: 8779262763683201687} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &6135228682338357176 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 575312753228297204} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10100, guid: 0000000000000000e000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!102 &3542259476824360018 +TextMesh: + serializedVersion: 3 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 575312753228297204} + m_Text: Player Name + m_OffsetZ: 0 + m_CharacterSize: 1 + m_LineSpacing: 1 + m_Anchor: 7 + m_Alignment: 1 + m_TabSize: 4 + m_FontSize: 100 + m_FontStyle: 0 + m_RichText: 1 + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_Color: + serializedVersion: 2 + rgba: 3238002687 +--- !u!1 &3187471305177936096 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8779262763683201687} + m_Layer: 0 + m_Name: FloatingInfo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8779262763683201687 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3187471305177936096} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 2.15, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5872215246660754301} + m_Father: {fileID: 9105303183089727062} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &7726143196833681180 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2977242866262118958} + m_Layer: 0 + m_Name: CameraTarget + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2977242866262118958 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7726143196833681180} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 2, z: -5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 9105303183089727062} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &9105303182223144758 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303182223144759} + - component: {fileID: 9105303182223144757} + - component: {fileID: 9105303182223144756} + m_Layer: 0 + m_Name: Cross (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303182223144759 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182223144758} + m_LocalRotation: {x: 0.7071068, y: -0, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.29199994, y: 0.68700004, z: 0} + m_LocalScale: {x: 0.034146547, y: 0.16708128, z: 0.066153266} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &9105303182223144757 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182223144758} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303182223144756 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182223144758} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0cb2aedfe1c0146808538c1b8ae2b1ab, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303182255863695 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303182255863692} + - component: {fileID: 9105303182255863682} + - component: {fileID: 9105303182255863693} + m_Layer: 0 + m_Name: Body + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303182255863692 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182255863695} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 0.901, z: 0} + m_LocalScale: {x: 0.38589802, y: 1.7807856, z: 0.38589802} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &9105303182255863682 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182255863695} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303182255863693 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182255863695} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6a1d409bf7eea44168084517c7ee81cf, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303182365644255 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303182365644252} + - component: {fileID: 9105303182365644242} + - component: {fileID: 9105303182365644253} + m_Layer: 0 + m_Name: Cross (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303182365644252 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182365644255} + m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: -0.5} + m_LocalPosition: {x: 0, y: 1.602, z: 0.22600007} + m_LocalScale: {x: 0.034146544, y: 0.16708137, z: 0.06615327} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: -90, y: 90, z: 0} +--- !u!33 &9105303182365644242 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182365644255} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303182365644253 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303182365644255} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0cb2aedfe1c0146808538c1b8ae2b1ab, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183019705939 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183019705936} + - component: {fileID: 9105303183019705942} + - component: {fileID: 9105303183019705937} + m_Layer: 0 + m_Name: Cross + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183019705936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183019705939} + m_LocalRotation: {x: -0, y: -0, z: -0, w: -1} + m_LocalPosition: {x: 0.288, y: 0.68700004, z: 0} + m_LocalScale: {x: 0.034146547, y: 0.16708137, z: 0.06615327} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &9105303183019705942 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183019705939} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183019705937 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183019705939} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0cb2aedfe1c0146808538c1b8ae2b1ab, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183046110716 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183046110717} + - component: {fileID: 9105303183046110707} + - component: {fileID: 9105303183046110706} + m_Layer: 0 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183046110717 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183046110716} + m_LocalRotation: {x: -0.3501483, y: 0.6143258, z: 0.18720065, w: -0.6818767} + m_LocalPosition: {x: 0.23500001, y: 0.9109, z: -0.082999945} + m_LocalScale: {x: 0.055933595, y: 0.29551184, z: 0.048371915} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 14.33, y: 90, z: -45.034} +--- !u!33 &9105303183046110707 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183046110716} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183046110706 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183046110716} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0eb01134dad314f879704d594ca8a7b2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183055541652 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183055541653} + - component: {fileID: 9105303183055541675} + - component: {fileID: 9105303183055541674} + m_Layer: 0 + m_Name: Cross + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183055541653 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183055541652} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0, y: 1.602, z: 0.22200012} + m_LocalScale: {x: 0.03414654, y: 0.16708137, z: 0.066153266} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &9105303183055541675 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183055541652} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183055541674 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183055541652} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0cb2aedfe1c0146808538c1b8ae2b1ab, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183086384153 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183086384158} + - component: {fileID: 9105303183086384156} + - component: {fileID: 9105303183086384159} + m_Layer: 0 + m_Name: Bag + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183086384158 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183086384153} + m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 0.249, y: 0.68500006, z: 0} + m_LocalScale: {x: 0.43514544, y: 0.29551184, z: 0.09221598} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!33 &9105303183086384156 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183086384153} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183086384159 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183086384153} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0eb01134dad314f879704d594ca8a7b2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183089727057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183089727062} + - component: {fileID: 4511077071076738942} + - component: {fileID: -3238995969169225930} + - component: {fileID: -1736107136792142439} + - component: {fileID: 2971830291389855711} + - component: {fileID: -2538202292241907205} + - component: {fileID: 689587676988298619} + - component: {fileID: -4146909649929904479} + - component: {fileID: -6188707919164901343} + m_Layer: 0 + m_Name: CharacterMedic + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183089727062 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7648894086210803939} + - {fileID: 8779262763683201687} + - {fileID: 2977242866262118958} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4511077071076738942 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e04a8cb02afdc4e778925020d233d718, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + floatingInfo: {fileID: 8779262763683201687} + characterNumber: 0 + textMeshName: {fileID: 3542259476824360018} + playerName: + characterColour: {r: 0, g: 0, b: 0, a: 0} + characterRenderers: + - {fileID: 9105303183937996605} + - {fileID: 9105303183086384159} + - {fileID: 9105303183046110706} + - {fileID: 9105303183986044559} +--- !u!54 &-3238995969169225930 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!136 &-1736107136792142439 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 1 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!143 &2971830291389855711 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &-2538202292241907205 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1526970849 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &689587676988298619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 9105303183089727062} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-4146909649929904479 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f81b59082839c2e40938767457bb91ae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 2971830291389855711} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!114 &-6188707919164901343 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183089727057} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db9418a9e709a7844acac42de096cba6, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterSelection: {fileID: 4511077071076738942} + cameraTarget: {fileID: 2977242866262118958} + sceneReferencer: {fileID: 0} + cameraObj: {fileID: 0} +--- !u!1 &9105303183937996607 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183937996604} + - component: {fileID: 9105303183937996594} + - component: {fileID: 9105303183937996605} + m_Layer: 0 + m_Name: Band + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183937996604 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183937996607} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.602, z: 0} + m_LocalScale: {x: 0.43514535, y: 0.20080449, z: 0.43514535} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &9105303183937996594 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183937996607} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183937996605 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183937996607} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0eb01134dad314f879704d594ca8a7b2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &9105303183986044553 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105303183986044558} + - component: {fileID: 9105303183986044556} + - component: {fileID: 9105303183986044559} + m_Layer: 0 + m_Name: Handle (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9105303183986044558 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183986044553} + m_LocalRotation: {x: 0.16554464, y: 0.68745524, z: -0.33054695, w: -0.62509125} + m_LocalPosition: {x: 0.23600006, y: 0.9189, z: 0.09200001} + m_LocalScale: {x: 0.05593358, y: 0.2955118, z: 0.0483719} + m_Children: [] + m_Father: {fileID: 7648894086210803939} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 14.33, y: 90, z: 41.409} +--- !u!33 &9105303183986044556 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183986044553} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &9105303183986044559 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105303183986044553} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0eb01134dad314f879704d594ca8a7b2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab.meta new file mode 100644 index 0000000..2355155 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c9bc5d2c4dbfe45698e8df60415a0b9b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/Characters/CharacterMedic.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab b/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab new file mode 100644 index 0000000..c9f521d --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab @@ -0,0 +1,66 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &193462938415849019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 193462938415849021} + - component: {fileID: 193462938415849020} + - component: {fileID: -4156899249651906285} + m_Layer: 0 + m_Name: PlayerEmpty + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &193462938415849021 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 193462938415849019} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &193462938415849020 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 193462938415849019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1488909710 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-4156899249651906285 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 193462938415849019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ef22691ec32ce4b5f8dd75e8330b07ce, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 diff --git a/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab.meta b/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab.meta new file mode 100644 index 0000000..8881d0e --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 622ba1e4799554a45a3443be2c75dace +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Prefabs/PlayerEmpty.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts.meta new file mode 100644 index 0000000..41541e7 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c897cb6114e43499aa657bf9d7518066 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs new file mode 100644 index 0000000..408f329 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs @@ -0,0 +1,194 @@ +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; +using static Mirror.Examples.CharacterSelection.NetworkManagerCharacterSelection; + +namespace Mirror.Examples.CharacterSelection +{ + public class CanvasReferencer : MonoBehaviour + { + // Make sure to attach these Buttons in the Inspector + public Button buttonExit, buttonNextCharacter, buttonGo, buttonColour, buttonColourReset; + public Text textTitle, textHealth, textSpeed, textAttack, textAbilities; + public InputField inputFieldPlayerName; + + public Transform podiumPosition; + private int currentlySelectedCharacter = 1; + private CharacterData characterData; + private GameObject currentInstantiatedCharacter; + private CharacterSelection characterSelection; + public SceneReferencer sceneReferencer; + public Camera cameraObj; + + private void Start() + { + characterData = CharacterData.characterDataSingleton; + if (characterData == null) + { + Debug.Log("Add CharacterData prefab singleton into the scene."); + return; + } + + buttonExit.onClick.AddListener(ButtonExit); + buttonNextCharacter.onClick.AddListener(ButtonNextCharacter); + buttonGo.onClick.AddListener(ButtonGo); + buttonColour.onClick.AddListener(ButtonColour); + buttonColourReset.onClick.AddListener(ButtonColourReset); + //Adds a listener to the main input field and invokes a method when the value changes. + inputFieldPlayerName.onValueChanged.AddListener(delegate { InputFieldChangedPlayerName(); }); + + LoadData(); + SetupCharacters(); + } + + public void ButtonExit() + { + //Debug.Log("ButtonExit"); + if (sceneReferencer) + { + sceneReferencer.CloseCharacterSelection(); + } + } + + public void ButtonGo() + { + //Debug.Log("ButtonGo"); + + // presumes we're already in-game + if (sceneReferencer && NetworkClient.active) + { + + // You could check if prefab (character number) has not changed, and if so just update the sync vars and hooks of current prefab, this would call a command from your player. + // this is not fully setup for this example, but provides a minor template to follow if needed + //NetworkClient.localPlayer.GetComponent().CmdSetupCharacter(StaticVariables.playerName, StaticVariables.characterColour); + + CreateCharacterMessage _characterMessage = new CreateCharacterMessage + { + playerName = StaticVariables.playerName, + characterNumber = StaticVariables.characterNumber, + characterColour = StaticVariables.characterColour + }; + + ReplaceCharacterMessage replaceCharacterMessage = new ReplaceCharacterMessage + { + createCharacterMessage = _characterMessage + }; + NetworkManagerCharacterSelection.singleton.ReplaceCharacter(replaceCharacterMessage); + sceneReferencer.CloseCharacterSelection(); + } + else + { + // not in-game + SceneManager.LoadScene("MirrorCharacterSelection"); + } + } + + public void ButtonNextCharacter() + { + //Debug.Log("ButtonNextCharacter"); + + currentlySelectedCharacter += 1; + if (currentlySelectedCharacter >= characterData.characterPrefabs.Length) + { + currentlySelectedCharacter = 1; + } + SetupCharacters(); + + StaticVariables.characterNumber = currentlySelectedCharacter; + } + + public void ButtonColour() + { + //Debug.Log("ButtonColour"); + StaticVariables.characterColour = Random.ColorHSV(0f, 1f, 1f, 1f, 0f, 1f); + SetupCharacterColours(); + } + + public void ButtonColourReset() + { + //Debug.Log("ButtonColourReset "); + StaticVariables.characterColour = new Color(0, 0, 0, 0); + SetupCharacters(); + } + + private void SetupCharacters() + { + textTitle.text = "" + characterData.characterTitles[currentlySelectedCharacter]; + textHealth.text = "Health: " + characterData.characterHealths[currentlySelectedCharacter]; + textSpeed.text = "Speed: " + characterData.characterSpeeds[currentlySelectedCharacter]; + textAttack.text = "Attack: " + characterData.characterAttack[currentlySelectedCharacter]; + textAbilities.text = "Abilities:\n" + characterData.characterAbilities[currentlySelectedCharacter]; + + if (currentInstantiatedCharacter) + { + Destroy(currentInstantiatedCharacter); + } + currentInstantiatedCharacter = Instantiate(characterData.characterPrefabs[currentlySelectedCharacter]); + currentInstantiatedCharacter.transform.position = podiumPosition.position; + currentInstantiatedCharacter.transform.rotation = podiumPosition.rotation; + characterSelection = currentInstantiatedCharacter.GetComponent(); + currentInstantiatedCharacter.transform.SetParent(this.transform.root); + + SetupCharacterColours(); + SetupPlayerName(); + + if (cameraObj) + { + characterSelection.floatingInfo.forward = cameraObj.transform.forward; + } + } + + public void SetupCharacterColours() + { + // Debug.Log("SetupCharacterColours"); + if (StaticVariables.characterColour != new Color(0, 0, 0, 0)) + { + characterSelection.characterColour = StaticVariables.characterColour; + characterSelection.AssignColours(); + } + } + + public void InputFieldChangedPlayerName() + { + //Debug.Log("InputFieldChangedPlayerName"); + StaticVariables.playerName = inputFieldPlayerName.text; + SetupPlayerName(); + } + + public void SetupPlayerName() + { + //Debug.Log("SetupPlayerName"); + if (characterSelection) + { + characterSelection.playerName = StaticVariables.playerName; + characterSelection.AssignName(); + } + } + + public void LoadData() + { + // check if the static save data has been pre-set + if (StaticVariables.playerName != "") + { + if (inputFieldPlayerName) + { + inputFieldPlayerName.text = StaticVariables.playerName; + } + } + else + { + StaticVariables.playerName = "Player Name"; + } + + // check that prefab is set, or exists for saved character number data + if (StaticVariables.characterNumber > 0 && StaticVariables.characterNumber < characterData.characterPrefabs.Length) + { + currentlySelectedCharacter = StaticVariables.characterNumber; + } + else + { + StaticVariables.characterNumber = currentlySelectedCharacter; + } + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs.meta new file mode 100644 index 0000000..14f9806 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: faef105eb77a94bbaacfe57f48968e19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/CanvasReferencer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs new file mode 100644 index 0000000..f7f7f22 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace Mirror.Examples.CharacterSelection +{ + public class CharacterData : MonoBehaviour + { + // A reference data script for most things character and customisation related. + + public static CharacterData characterDataSingleton { get; private set; } + + public GameObject[] characterPrefabs; + public string[] characterTitles; + public int[] characterHealths; + public float[] characterSpeeds; + public int[] characterAttack; + public string[] characterAbilities; + + public void Awake() + { + characterDataSingleton = this; + } + + } + +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs.meta new file mode 100644 index 0000000..7ddecb1 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f5fc49087bdc848b2aefe5c91858c7b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterData.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs new file mode 100644 index 0000000..7a90a1d --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.CharacterSelection +{ + public class CharacterSelection : NetworkBehaviour + { + public Transform floatingInfo; + + [SyncVar] + public int characterNumber = 0; + + public TextMesh textMeshName; + [SyncVar(hook = nameof(HookSetName))] + public string playerName = ""; + + void HookSetName(string _old, string _new) + { + //Debug.Log("HookSetName"); + AssignName(); + } + + [SyncVar(hook = nameof(HookSetColor))] + public Color characterColour; + private Material cachedMaterial; + public MeshRenderer[] characterRenderers; + + void HookSetColor(Color _old, Color _new) + { + //Debug.Log("HookSetColor"); + AssignColours(); + } + + public void AssignColours() + { + foreach (MeshRenderer meshRenderer in characterRenderers) + { + cachedMaterial = meshRenderer.material; + cachedMaterial.color = characterColour; + } + } + + void OnDestroy() + { + if (cachedMaterial) { Destroy(cachedMaterial); } + } + + public void AssignName() + { + textMeshName.text = playerName; + } + + // To change server controlled sync vars, clients end Commands, and the hooks will fire + // Although not used in this example, we could change some character aspects without replacing current prefab. + //[Command] + //public void CmdSetupCharacter(string _playerName, Color _characterColour) + //{ + // playerName = _playerName; + // characterColour = _characterColour; + //} + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs.meta new file mode 100644 index 0000000..e73fbf1 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: e04a8cb02afdc4e778925020d233d718 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/CharacterSelection.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs new file mode 100644 index 0000000..7fe1efc --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs @@ -0,0 +1,135 @@ +using UnityEngine; + +namespace Mirror.Examples.CharacterSelection +{ + [AddComponentMenu("")] + public class NetworkManagerCharacterSelection : NetworkManager + { + // See the scene 'SceneMapSpawnWithNoCharacter', to spawn as empty player. + // 'SceneMap' will auto spawn as random player character. + // Compare Network Manager inspector setups to see the difference between the two. + // Either of these allow selecting character after spawning in too. + public bool SpawnAsCharacter = true; + + public static new NetworkManagerCharacterSelection singleton => (NetworkManagerCharacterSelection)NetworkManager.singleton; + private CharacterData characterData; + + public override void Awake() + { + characterData = CharacterData.characterDataSingleton; + if (characterData == null) + { + Debug.Log("Add CharacterData prefab singleton into the scene."); + return; + } + base.Awake(); + } + + public struct CreateCharacterMessage : NetworkMessage + { + public string playerName; + public int characterNumber; + public Color characterColour; + } + + public struct ReplaceCharacterMessage : NetworkMessage + { + public CreateCharacterMessage createCharacterMessage; + } + + public override void OnStartServer() + { + base.OnStartServer(); + + NetworkServer.RegisterHandler(OnCreateCharacter); + NetworkServer.RegisterHandler(OnReplaceCharacterMessage); + } + + public override void OnClientConnect() + { + base.OnClientConnect(); + + if (SpawnAsCharacter) + { + // you can send the message here, or wherever else you want + CreateCharacterMessage characterMessage = new CreateCharacterMessage + { + playerName = StaticVariables.playerName, + characterNumber = StaticVariables.characterNumber, + characterColour = StaticVariables.characterColour + }; + + NetworkClient.Send(characterMessage); + } + } + + void OnCreateCharacter(NetworkConnectionToClient conn, CreateCharacterMessage message) + { + Transform startPos = GetStartPosition(); + + // check if the save data has been pre-set + if (message.playerName == "") + { + Debug.Log("OnCreateCharacter name invalid or not set, use random."); + message.playerName = "Player: " + UnityEngine.Random.Range(100, 1000); + } + + // check that prefab is set, or exists for saved character number data + // could be a cheater, or coding error, or different version conflict + if (message.characterNumber <= 0 || message.characterNumber >= characterData.characterPrefabs.Length) + { + Debug.Log("OnCreateCharacter prefab Invalid or not set, use random."); + message.characterNumber = UnityEngine.Random.Range(1, characterData.characterPrefabs.Length); + } + + // check if the save data has been pre-set + if (message.characterColour == new Color(0, 0, 0, 0)) + { + Debug.Log("OnCreateCharacter colour invalid or not set, use random."); + message.characterColour = Random.ColorHSV(0f, 1f, 1f, 1f, 0f, 1f); + } + + GameObject playerObject = startPos != null + ? Instantiate(characterData.characterPrefabs[message.characterNumber], startPos.position, startPos.rotation) + : Instantiate(characterData.characterPrefabs[message.characterNumber]); + + + // Apply data from the message however appropriate for your game + // Typically Player would be a component you write with syncvars or properties + CharacterSelection characterSelection = playerObject.GetComponent(); + characterSelection.playerName = message.playerName; + characterSelection.characterNumber = message.characterNumber; + characterSelection.characterColour = message.characterColour; + + // call this to use this gameobject as the primary controller + NetworkServer.AddPlayerForConnection(conn, playerObject); + } + + void OnReplaceCharacterMessage(NetworkConnectionToClient conn, ReplaceCharacterMessage message) + { + // Cache a reference to the current player object + GameObject oldPlayer = conn.identity.gameObject; + + GameObject playerObject = Instantiate(characterData.characterPrefabs[message.createCharacterMessage.characterNumber], oldPlayer.transform.position, oldPlayer.transform.rotation); + + // Instantiate the new player object and broadcast to clients + NetworkServer.ReplacePlayerForConnection(conn, playerObject, ReplacePlayerOptions.KeepActive); + + // Apply data from the message however appropriate for your game + // Typically Player would be a component you write with syncvars or properties + CharacterSelection characterSelection = playerObject.GetComponent(); + characterSelection.playerName = message.createCharacterMessage.playerName; + characterSelection.characterNumber = message.createCharacterMessage.characterNumber; + characterSelection.characterColour = message.createCharacterMessage.characterColour; + + // Remove the previous player object that's now been replaced + // Delay is required to allow replacement to complete. + Destroy(oldPlayer, 0.1f); + } + + public void ReplaceCharacter(ReplaceCharacterMessage message) + { + NetworkClient.Send(message); + } + } +} diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs.meta new file mode 100644 index 0000000..b9b68a7 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 98c582433a349434990d734c5586d722 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/NetworkManagerCharacterSelection.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs new file mode 100644 index 0000000..e44fa8a --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs @@ -0,0 +1,22 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.CharacterSelection +{ + public class PlayerEmpty : NetworkBehaviour + { + private SceneReferencer sceneReferencer; + + public override void OnStartAuthority() + { + // enable UI located in the scene, after empty player spawns in. +#if UNITY_2022_2_OR_NEWER + sceneReferencer = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + sceneReferencer = GameObject.FindObjectOfType(); +#endif + sceneReferencer.GetComponent().enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs.meta new file mode 100644 index 0000000..af2294c --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: ef22691ec32ce4b5f8dd75e8330b07ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/PlayerEmpty.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs new file mode 100644 index 0000000..6c3ac39 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace Mirror.Examples.CharacterSelection +{ + public class SceneCamera : NetworkBehaviour + { + [Header("Components")] + [SerializeField] CharacterSelection characterSelection; + [SerializeField] Transform cameraTarget; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] SceneReferencer sceneReferencer; + [ReadOnly, SerializeField] Transform cameraObj; + + protected override void OnValidate() + { + base.OnValidate(); + Reset(); + } + + void Reset() + { + characterSelection = GetComponent(); + cameraTarget = transform.Find("CameraTarget"); + this.enabled = false; + } + + public override void OnStartAuthority() + { +#if UNITY_2022_2_OR_NEWER + sceneReferencer = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + sceneReferencer = GameObject.FindObjectOfType(); +#endif + + cameraObj = sceneReferencer.cameraObject.transform; + + this.enabled = true; + } + + public override void OnStopAuthority() + { + this.enabled = false; + } + + void Update() + { + if (!Application.isFocused) + return; + + if (cameraObj && characterSelection) + characterSelection.floatingInfo.forward = cameraObj.transform.forward; + + if (cameraObj && cameraTarget) + cameraObj.SetPositionAndRotation(cameraTarget.position, cameraTarget.rotation); + } + } +} diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs.meta new file mode 100644 index 0000000..98196df --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: db9418a9e709a7844acac42de096cba6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/SceneCamera.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs new file mode 100644 index 0000000..2a53fcf --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.CharacterSelection +{ + public class SceneReferencer : MonoBehaviour + { + // Make sure to attach these Buttons in the Inspector + public Button buttonCharacterSelection; + + private CharacterData characterData; + public GameObject characterSelectionObject; + public GameObject sceneObjects; + public GameObject cameraObject; + + private void Start() + { + characterData = CharacterData.characterDataSingleton; + if (characterData == null) + { + Debug.Log("Add CharacterData prefab singleton into the scene."); + return; + } + + buttonCharacterSelection.onClick.AddListener(ButtonCharacterSelection); + } + + public void ButtonCharacterSelection() + { + // server-only mode should not press this button + //Debug.Log("ButtonCharacterSelection"); + cameraObject.SetActive(false); + sceneObjects.SetActive(false); + characterSelectionObject.SetActive(true); + this.GetComponent().enabled = false; + } + + public void CloseCharacterSelection() + { + //Debug.Log("CloseCharacterSelection"); + cameraObject.SetActive(true); + characterSelectionObject.SetActive(false); + sceneObjects.SetActive(true); + this.GetComponent().enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs.meta new file mode 100644 index 0000000..b016bba --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f45e025c29e20480cb3d9ab86918814a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/SceneReferencer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs new file mode 100644 index 0000000..62d8c76 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace Mirror.Examples.CharacterSelection +{ + // A fun little bob script for characters. + // You could reference this and change values depending on characters state, idle, walk, run. + + public class ScriptAnimations : MonoBehaviour + { + public float minimum = 0.1f; + public float maximum = 0.5f; + + private float yPos; + public float bounceSpeed = 3; + private float yStartPosition; + + private void Start() + { + yStartPosition = this.transform.localPosition.y; + } + + void Update() + { + float sinValue = Mathf.Sin(Time.time * bounceSpeed); + + yPos = Mathf.Lerp(maximum, minimum, Mathf.Abs((1.0f + sinValue) / 2.0f)); + transform.localPosition = new Vector3(transform.localPosition.x, yStartPosition + yPos, transform.localPosition.z); + } + } + + //credits https://stackoverflow.com/questions/67322860/how-do-i-make-a-simple-idle-bobbing-motion-animation + +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs.meta new file mode 100644 index 0000000..7a43568 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 0f36e96df6ff2459992432717c975c84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/ScriptAnimations.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs b/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs new file mode 100644 index 0000000..858c9ad --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace Mirror.Examples.CharacterSelection +{ + // we will use static variables to pass data between scenes + // this could also be done using other methods + public class StaticVariables : MonoBehaviour + { + public static string playerName = ""; + public static int characterNumber = 0; + public static Color characterColour; + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs.meta b/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs.meta new file mode 100644 index 0000000..997db89 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1d335b50444484132bf9affd60327c5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Scripts/StaticVariables.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/Textures.meta b/Assets/Mirror/Examples/CharacterSelection/Textures.meta new file mode 100644 index 0000000..a95876f --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Textures.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0726271d46f79488aaa1b2adc2ad08ff +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/CharacterSelection/Textures/IconRandomColour.png b/Assets/Mirror/Examples/CharacterSelection/Textures/IconRandomColour.png new file mode 100644 index 0000000000000000000000000000000000000000..741927287e7fd8c35af14aa2a8743e963035b3d1 GIT binary patch literal 89302 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

smYEjzdcr=yAxF}%Q}C?U~4ut=QQKC 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg.meta b/Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg.meta new file mode 100644 index 0000000..3a352d3 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 1d05f8485741f4d4ca94e613ba38db65 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/Textures/dirtMoon.jpg + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt b/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt new file mode 100644 index 0000000..1995411 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt @@ -0,0 +1,13 @@ +# Character Selection Example + +Three scenes, each provide a slightly different approach towards selecting characters and customisations. + +1: MirrorCharacterSelectionPreScene +This is an offline scene, allows players to select data, which is then saved and passed across to other scenes using static variables. +Once selected, the map loads "MirrorCharacterSelection", press Start Host, or Client to play. (remember to add scenes to build settings) + +2: MirrorCharacterSelection +This scene spawns with a character (randomised), and players have an option using the UI to change this. + +3: MirrorCharacterSelectionNoCharacter +Spawns an empty player prefab, then players chose which character using the UI. \ No newline at end of file diff --git a/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt.meta b/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt.meta new file mode 100644 index 0000000..4a32427 --- /dev/null +++ b/Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c6aefc445c18946b2ae670e81fa2d9ed +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CharacterSelection/_ReadMe.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat.meta b/Assets/Mirror/Examples/Chat.meta new file mode 100644 index 0000000..1b51dde --- /dev/null +++ b/Assets/Mirror/Examples/Chat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92165d23a248449f58d0be75d794a127 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Prefabs.meta b/Assets/Mirror/Examples/Chat/Prefabs.meta new file mode 100644 index 0000000..f3f82c4 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55a4e4e8824ec4e329adf12e2cfb02a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab new file mode 100644 index 0000000..75bf775 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5075528875289742095 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3351063249001228125} + - component: {fileID: 114398755512196590} + - component: {fileID: 718303009120396421} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3351063249001228125 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 718.76324, y: 411.311, z: -4.8041315} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &114398755512196590 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2840517625 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &718303009120396421 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5075528875289742095} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3addc5ad220944ed6888319897606739, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + playerName: diff --git a/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..138817d --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Prefabs/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e5905ffa27de84009b346b49d518ba03 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Prefabs/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scenes.meta b/Assets/Mirror/Examples/Chat/Scenes.meta new file mode 100644 index 0000000..ac2b33e --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 71f6f21bb51d14dc0b231a8488826aac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity b/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity new file mode 100644 index 0000000..4bd7de1 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity @@ -0,0 +1,3706 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.012745098, g: 0.07450981, b: 0.19901961, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &20782995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 20782996} + - component: {fileID: 20782998} + - component: {fileID: 20782997} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &20782996 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 851154180} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &20782997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.39215687} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &20782998 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20782995} + m_CullTransparentMesh: 0 +--- !u!1 &75860995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 75860996} + - component: {fileID: 75860999} + - component: {fileID: 75860998} + - component: {fileID: 75860997} + m_Layer: 5 + m_Name: ChatPanel + m_TagString: ChatWindow + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &75860996 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 762534976} + - {fileID: 1731300362} + - {fileID: 1863915625} + - {fileID: 1231350850} + - {fileID: 1286463573} + m_Father: {fileID: 719573003} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -40.000008, y: -40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &75860997 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_EffectDistance: {x: 10, y: -10} + m_UseGraphicAlpha: 1 +--- !u!114 &75860998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.92941177} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &75860999 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 75860995} + m_CullTransparentMesh: 0 +--- !u!1 &90143746 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 90143747} + - component: {fileID: 90143749} + - component: {fileID: 90143748} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &90143747 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1231350850} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &90143748 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &90143749 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 90143746} + m_CullTransparentMesh: 0 +--- !u!1 &107824418 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 107824419} + - component: {fileID: 107824421} + - component: {fileID: 107824420} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &107824419 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1063265579} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &107824420 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0.5019608, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Start Client +--- !u!222 &107824421 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 107824418} + m_CullTransparentMesh: 0 +--- !u!1 &423302019 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 423302020} + - component: {fileID: 423302023} + - component: {fileID: 423302022} + - component: {fileID: 423302021} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &423302020 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 731902021} + m_Father: {fileID: 1863915625} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &423302021 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1616857743} + m_HandleRect: {fileID: 1616857742} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &423302022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &423302023 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 423302019} + m_CullTransparentMesh: 0 +--- !u!1 &576238261 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 576238262} + - component: {fileID: 576238264} + - component: {fileID: 576238263} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &576238262 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 851154180} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &576238263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &576238264 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576238261} + m_CullTransparentMesh: 0 +--- !u!1 &591385423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 591385424} + - component: {fileID: 591385426} + - component: {fileID: 591385425} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &591385424 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027272348} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &591385425 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &591385426 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 591385423} + m_CullTransparentMesh: 0 +--- !u!1 &637644698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 637644699} + - component: {fileID: 637644701} + - component: {fileID: 637644700} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &637644699 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 637644698} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1731300362} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &637644700 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 637644698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X +--- !u!222 &637644701 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 637644698} + m_CullTransparentMesh: 1 +--- !u!1 &719572997 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 719573003} + - component: {fileID: 719573002} + - component: {fileID: 719573001} + - component: {fileID: 719573000} + - component: {fileID: 719572999} + - component: {fileID: 719572998} + m_Layer: 5 + m_Name: ChatUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &719572998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2c102f62d739545269250f48327d4429, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + chatHistory: {fileID: 827598817} + scrollbar: {fileID: 423302021} + chatMessage: {fileID: 1231350851} + sendButton: {fileID: 1286463574} +--- !u!114 &719572999 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 2564614208 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &719573000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 823 +--- !u!114 &719573001 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &719573002 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &719573003 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719572997} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 75860996} + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &719610385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 719610386} + - component: {fileID: 719610388} + - component: {fileID: 719610387} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &719610386 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1231350850} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &719610387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.39215687} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text and press Enter or click Send... +--- !u!222 &719610388 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 719610385} + m_CullTransparentMesh: 0 +--- !u!1 &731902020 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 731902021} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &731902021 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 731902020} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1616857742} + m_Father: {fileID: 423302020} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &762534975 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 762534976} + - component: {fileID: 762534978} + - component: {fileID: 762534977} + m_Layer: 5 + m_Name: Header + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &762534976 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 75860996} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -30} + m_SizeDelta: {x: 1211, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &762534977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Mirror Chat Example +--- !u!222 &762534978 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 762534975} + m_CullTransparentMesh: 0 +--- !u!1 &780870085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 780870086} + - component: {fileID: 780870089} + - component: {fileID: 780870088} + - component: {fileID: 780870087} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &780870086 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1335915325} + m_Father: {fileID: 1863915625} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &780870087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &780870088 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_CullTransparentMesh: 0 +--- !u!114 &780870089 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 780870085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &827598815 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 827598816} + - component: {fileID: 827598818} + - component: {fileID: 827598817} + m_Layer: 5 + m_Name: ChatHistory + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &827598816 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1335915325} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &827598817 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 0 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: +--- !u!222 &827598818 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 827598815} + m_CullTransparentMesh: 0 +--- !u!1 &851154179 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 851154180} + - component: {fileID: 851154183} + - component: {fileID: 851154182} + - component: {fileID: 851154181} + m_Layer: 5 + m_Name: UsernameInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &851154180 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 20782996} + - {fileID: 576238262} + m_Father: {fileID: 1499096249} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 381, y: -175} + m_SizeDelta: {x: 250, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &851154181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 851154182} + m_TextComponent: {fileID: 576238263} + m_Placeholder: {fileID: 20782997} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1783103024} + m_MethodName: SetPlayername + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1453327789} + m_MethodName: ToggleButtons + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &851154182 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &851154183 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 851154179} + m_CullTransparentMesh: 0 +--- !u!1 &1018203013 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1018203014} + - component: {fileID: 1018203016} + - component: {fileID: 1018203015} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1018203014 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1286463573} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1018203015 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0.5019608, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Send + +' +--- !u!222 &1018203016 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018203013} + m_CullTransparentMesh: 0 +--- !u!1 &1027272347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1027272348} + - component: {fileID: 1027272351} + - component: {fileID: 1027272350} + - component: {fileID: 1027272349} + m_Layer: 5 + m_Name: NetworkAddressInput + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1027272348 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1170876675} + - {fileID: 591385424} + m_Father: {fileID: 1499096249} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 381, y: -126} + m_SizeDelta: {x: 250, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1027272349 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1027272350} + m_TextComponent: {fileID: 591385425} + m_Placeholder: {fileID: 1170876676} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1783103025} + m_MethodName: SetHostname + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1027272350 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1027272351 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027272347} + m_CullTransparentMesh: 0 +--- !u!1 &1063265578 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1063265579} + - component: {fileID: 1063265582} + - component: {fileID: 1063265581} + - component: {fileID: 1063265580} + m_Layer: 5 + m_Name: ClientButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1063265579 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 107824419} + m_Father: {fileID: 1499096249} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 415, y: -254} + m_SizeDelta: {x: 220, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1063265580 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 0 + m_TargetGraphic: {fileID: 1063265581} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1453327784} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1783103025} + m_MethodName: StartClient + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &1063265581 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1063265582 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063265578} + m_CullTransparentMesh: 0 +--- !u!1 &1170876674 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1170876675} + - component: {fileID: 1170876677} + - component: {fileID: 1170876676} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1170876675 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1027272348} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1170876676 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.39215687} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: localhost +--- !u!222 &1170876677 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1170876674} + m_CullTransparentMesh: 0 +--- !u!1 &1231350849 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1231350850} + - component: {fileID: 1231350853} + - component: {fileID: 1231350852} + - component: {fileID: 1231350851} + m_Layer: 5 + m_Name: MessageField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1231350850 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 719610386} + - {fileID: 90143747} + m_Father: {fileID: 75860996} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 26, y: 12} + m_SizeDelta: {x: -176.4, y: 41} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1231350851 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1231350852} + m_TextComponent: {fileID: 90143748} + m_Placeholder: {fileID: 719610387} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 719572998} + m_MethodName: OnEndEdit + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 719572998} + m_MethodName: ToggleButton + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1231350852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1231350853 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1231350849} + m_CullTransparentMesh: 0 +--- !u!1 &1286463572 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1286463573} + - component: {fileID: 1286463576} + - component: {fileID: 1286463575} + - component: {fileID: 1286463574} + m_Layer: 5 + m_Name: SendButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1286463573 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1018203014} + m_Father: {fileID: 75860996} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -26, y: 12} + m_SizeDelta: {x: 116.9, y: 41} + m_Pivot: {x: 1, y: 0} +--- !u!114 &1286463574 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 0 + m_TargetGraphic: {fileID: 1286463575} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 719572998} + m_MethodName: SendMessage + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1286463575 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1286463576 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1286463572} + m_CullTransparentMesh: 0 +--- !u!1 &1335915324 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1335915325} + - component: {fileID: 1335915327} + - component: {fileID: 1335915326} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1335915325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 827598816} + m_Father: {fileID: 780870086} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 1, y: 0} + m_SizeDelta: {x: -1, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1335915326 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1335915327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1335915324} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 5 + m_Top: 5 + m_Bottom: 5 + m_ChildAlignment: 0 + m_Spacing: 2 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &1453327784 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1453327788} + - component: {fileID: 1453327787} + - component: {fileID: 1453327786} + - component: {fileID: 1453327785} + - component: {fileID: 1453327789} + m_Layer: 5 + m_Name: LoginUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1453327785 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 823 +--- !u!114 &1453327786 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1453327787 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1453327788 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1499096249} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1453327789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1453327784} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7a77ca56c9d91af4b81b73a9907d6112, type: 3} + m_Name: + m_EditorClassIdentifier: + networkAddressInput: {fileID: 1027272349} + usernameInput: {fileID: 851154181} + hostButton: {fileID: 1904406266} + clientButton: {fileID: 1063265580} + errorText: {fileID: 1580038555} +--- !u!1 &1481045372 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1481045373} + - component: {fileID: 1481045375} + - component: {fileID: 1481045374} + m_Layer: 5 + m_Name: UsernameLabel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1481045373 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 172, y: -175} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1481045374 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'User name:' +--- !u!222 &1481045375 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1481045372} + m_CullTransparentMesh: 0 +--- !u!1 &1499096248 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1499096249} + - component: {fileID: 1499096252} + - component: {fileID: 1499096251} + - component: {fileID: 1499096250} + m_Layer: 5 + m_Name: LoginPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1499096249 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1909588651} + - {fileID: 1995652016} + - {fileID: 1027272348} + - {fileID: 1481045373} + - {fileID: 851154180} + - {fileID: 1904406265} + - {fileID: 1063265579} + - {fileID: 1580038557} + m_Father: {fileID: 1453327788} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 600, y: 400} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1499096250 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 10, y: -10} + m_UseGraphicAlpha: 1 +--- !u!114 &1499096251 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.92941177} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1499096252 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1499096248} + m_CullTransparentMesh: 0 +--- !u!1 &1569758148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1569758149} + - component: {fileID: 1569758151} + - component: {fileID: 1569758150} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1569758149 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1904406265} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1569758150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0.5019608, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Start Host +--- !u!222 &1569758151 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1569758148} + m_CullTransparentMesh: 0 +--- !u!1 &1580038554 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1580038557} + - component: {fileID: 1580038556} + - component: {fileID: 1580038555} + m_Layer: 5 + m_Name: ErrorText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &1580038555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580038554} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1580038556 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580038554} + m_CullTransparentMesh: 0 +--- !u!224 &1580038557 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1580038554} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -340} + m_SizeDelta: {x: 440, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1616857741 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1616857742} + - component: {fileID: 1616857744} + - component: {fileID: 1616857743} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1616857742 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 731902021} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1616857743 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1616857744 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1616857741} + m_CullTransparentMesh: 0 +--- !u!1 &1667679449 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1667679451} + - component: {fileID: 1667679450} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!108 &1667679450 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667679449} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1667679451 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1667679449} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1731300361 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1731300362} + - component: {fileID: 1731300365} + - component: {fileID: 1731300364} + - component: {fileID: 1731300363} + m_Layer: 5 + m_Name: ExitButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1731300362 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1731300361} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 637644699} + m_Father: {fileID: 75860996} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -20, y: -20} + m_SizeDelta: {x: 25, y: 25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1731300363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1731300361} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1731300364} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 719572998} + m_MethodName: ExitButtonOnClick + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1731300364 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1731300361} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1731300365 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1731300361} + m_CullTransparentMesh: 1 +--- !u!1 &1783103022 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1783103026} + - component: {fileID: 1783103025} + - component: {fileID: 1783103023} + - component: {fileID: 1783103024} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1783103023 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1783103024 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6e2e6b40604520d408bef0a5243a58cd, type: 3} + m_Name: + m_EditorClassIdentifier: + OnServerAuthenticated: + m_PersistentCalls: + m_Calls: [] + OnClientAuthenticated: + m_PersistentCalls: + m_Calls: [] + playerName: +--- !u!114 &1783103025 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0cd72391a563461f88eb3ddf120efef, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1783103023} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 1783103024} + playerPrefab: {fileID: 5075528875289742095, guid: e5905ffa27de84009b346b49d518ba03, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 +--- !u!4 &1783103026 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1783103022} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1863915624 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1863915625} + - component: {fileID: 1863915628} + - component: {fileID: 1863915627} + - component: {fileID: 1863915626} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1863915625 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 780870086} + - {fileID: 423302020} + m_Father: {fileID: 75860996} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 5} + m_SizeDelta: {x: -51.999992, y: -110} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1863915626 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1863915627 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_CullTransparentMesh: 0 +--- !u!114 &1863915628 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1863915624} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1335915325} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 1 + m_Elasticity: 0.01 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 100 + m_Viewport: {fileID: 780870086} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 423302021} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1897504366 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1897504369} + - component: {fileID: 1897504368} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &1897504368 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1897504366} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215688, g: 0.3019608, b: 0.47450984, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1897504369 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1897504366} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1904406264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1904406265} + - component: {fileID: 1904406268} + - component: {fileID: 1904406267} + - component: {fileID: 1904406266} + m_Layer: 5 + m_Name: HostButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1904406265 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1569758149} + m_Father: {fileID: 1499096249} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 185, y: -254} + m_SizeDelta: {x: 220, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1904406266 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 0 + m_TargetGraphic: {fileID: 1904406267} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1453327784} + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + - m_Target: {fileID: 1783103025} + m_MethodName: StartHost + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &1904406267 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1904406268 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1904406264} + m_CullTransparentMesh: 0 +--- !u!1 &1909588650 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1909588651} + - component: {fileID: 1909588653} + - component: {fileID: 1909588652} + m_Layer: 5 + m_Name: Header + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1909588651 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -55} + m_SizeDelta: {x: 350, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1909588652 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 35 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Mirror Chat Example +--- !u!222 &1909588653 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1909588650} + m_CullTransparentMesh: 0 +--- !u!1 &1923358029 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1923358032} + - component: {fileID: 1923358031} + - component: {fileID: 1923358030} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1923358030 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1923358031 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1923358032 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1923358029} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1995652015 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1995652016} + - component: {fileID: 1995652018} + - component: {fileID: 1995652017} + m_Layer: 5 + m_Name: ServerLabel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1995652016 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1499096249} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 172, y: -126} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1995652017 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: 'Server:' +--- !u!222 &1995652018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995652015} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity.meta b/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity.meta new file mode 100644 index 0000000..d4eda7f --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f4e8d4de4484e44bba666f2d1f66c73e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scenes/MirrorChat.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scripts.meta b/Assets/Mirror/Examples/Chat/Scripts.meta new file mode 100644 index 0000000..71858f4 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81da49d71176c41169a24259df78e50a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs new file mode 100644 index 0000000..efc0759 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs @@ -0,0 +1,213 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/* + Documentation: https://mirror-networking.gitbook.io/docs/components/network-authenticators + API Reference: https://mirror-networking.com/docs/api/Mirror.NetworkAuthenticator.html +*/ + +namespace Mirror.Examples.Chat +{ + [AddComponentMenu("")] + public class ChatAuthenticator : NetworkAuthenticator + { + readonly HashSet connectionsPendingDisconnect = new HashSet(); + internal static readonly HashSet playerNames = new HashSet(); + + [Header("Client Username")] + public string playerName; + + #region Messages + + public struct AuthRequestMessage : NetworkMessage + { + // use whatever credentials make sense for your game + // for example, you might want to pass the accessToken if using oauth + public string authUsername; + } + + public struct AuthResponseMessage : NetworkMessage + { + public byte code; + public string message; + } + + #endregion + + #region Server + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [UnityEngine.RuntimeInitializeOnLoadMethod] + static void ResetStatics() + { + playerNames.Clear(); + } + + ///

+ /// Called on server from StartServer to initialize the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStartServer() + { + // register a handler for the authentication request we expect from client + NetworkServer.RegisterHandler(OnAuthRequestMessage, false); + } + + /// + /// Called on server from StopServer to reset the Authenticator + /// Server message handlers should be registered in this method. + /// + public override void OnStopServer() + { + // unregister the handler for the authentication request + NetworkServer.UnregisterHandler(); + } + + /// + /// Called on server from OnServerConnectInternal when a client needs to authenticate + /// + /// Connection to client. + public override void OnServerAuthenticate(NetworkConnectionToClient conn) + { + // do nothing...wait for AuthRequestMessage from client + } + + /// + /// Called on server when the client's AuthRequestMessage arrives + /// + /// Connection to client. + /// The message payload + public void OnAuthRequestMessage(NetworkConnectionToClient conn, AuthRequestMessage msg) + { + Debug.Log($"Authentication Request: {msg.authUsername}"); + + if (connectionsPendingDisconnect.Contains(conn)) return; + + // check the credentials by calling your web server, database table, playfab api, or any method appropriate. + if (!playerNames.Contains(msg.authUsername)) + { + // Add the name to the HashSet + playerNames.Add(msg.authUsername); + + // Store username in authenticationData + // This will be read in Player.OnStartServer + // to set the playerName SyncVar. + conn.authenticationData = msg.authUsername; + + // create and send msg to client so it knows to proceed + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 100, + message = "Success" + }; + + conn.Send(authResponseMessage); + + // Accept the successful authentication + ServerAccept(conn); + } + else + { + connectionsPendingDisconnect.Add(conn); + + // create and send msg to client so it knows to disconnect + AuthResponseMessage authResponseMessage = new AuthResponseMessage + { + code = 200, + message = "Username already in use...try again" + }; + + conn.Send(authResponseMessage); + + // must set NetworkConnection isAuthenticated = false + conn.isAuthenticated = false; + + // disconnect the client after 1 second so that response message gets delivered + StartCoroutine(DelayedDisconnect(conn, 1f)); + } + } + + IEnumerator DelayedDisconnect(NetworkConnectionToClient conn, float waitTime) + { + yield return new WaitForSeconds(waitTime); + + // Reject the unsuccessful authentication + ServerReject(conn); + + yield return null; + + // remove conn from pending connections + connectionsPendingDisconnect.Remove(conn); + } + + #endregion + + #region Client + + // Called by UI element UsernameInput.OnValueChanged + public void SetPlayername(string username) + { + playerName = username; + LoginUI.instance.errorText.text = string.Empty; + LoginUI.instance.errorText.gameObject.SetActive(false); + } + + /// + /// Called on client from StartClient to initialize the Authenticator + /// Client message handlers should be registered in this method. + /// + public override void OnStartClient() + { + // register a handler for the authentication response we expect from server + NetworkClient.RegisterHandler(OnAuthResponseMessage, false); + } + + /// + /// Called on client from StopClient to reset the Authenticator + /// Client message handlers should be unregistered in this method. + /// + public override void OnStopClient() + { + // unregister the handler for the authentication response + NetworkClient.UnregisterHandler(); + } + + /// + /// Called on client from OnClientConnectInternal when a client needs to authenticate + /// + public override void OnClientAuthenticate() + { + NetworkClient.Send(new AuthRequestMessage { authUsername = playerName }); + } + + /// + /// Called on client when the server's AuthResponseMessage arrives + /// + /// The message payload + public void OnAuthResponseMessage(AuthResponseMessage msg) + { + if (msg.code == 100) + { + Debug.Log($"Authentication Response: {msg.code} {msg.message}"); + + // Authentication has been accepted + ClientAccept(); + } + else + { + Debug.LogError($"Authentication Response: {msg.code} {msg.message}"); + + // Authentication has been rejected + // StopHost works for both host client and remote clients + NetworkManager.singleton.StopHost(); + + // Do this AFTER StopHost so it doesn't get cleared / hidden by OnClientDisconnect + LoginUI.instance.errorText.text = msg.message; + LoginUI.instance.errorText.gameObject.SetActive(true); + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta new file mode 100644 index 0000000..d75ef15 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6e2e6b40604520d408bef0a5243a58cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scripts/ChatAuthenticator.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs new file mode 100644 index 0000000..c083174 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace Mirror.Examples.Chat +{ + [AddComponentMenu("")] + public class ChatNetworkManager : NetworkManager + { + // Called by UI element NetworkAddressInput.OnValueChanged + public void SetHostname(string hostname) + { + networkAddress = hostname; + } + + public override void OnServerDisconnect(NetworkConnectionToClient conn) + { + // remove player name from the HashSet + if (conn.authenticationData != null) + ChatAuthenticator.playerNames.Remove((string)conn.authenticationData); + + // remove connection from Dictionary of conn > names + ChatUI.connNames.Remove(conn); + + base.OnServerDisconnect(conn); + } + + public override void OnClientDisconnect() + { + base.OnClientDisconnect(); + LoginUI.instance.gameObject.SetActive(true); + LoginUI.instance.usernameInput.text = ""; + LoginUI.instance.usernameInput.ActivateInputField(); + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta new file mode 100644 index 0000000..5e07a36 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: d0cd72391a563461f88eb3ddf120efef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scripts/ChatNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs new file mode 100644 index 0000000..e8c8d0f --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs @@ -0,0 +1,100 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.Chat +{ + public class ChatUI : NetworkBehaviour + { + [Header("UI Elements")] + [SerializeField] Text chatHistory; + [SerializeField] Scrollbar scrollbar; + [SerializeField] InputField chatMessage; + [SerializeField] Button sendButton; + + // This is only set on client to the name of the local player + internal static string localPlayerName; + + // Server-only cross-reference of connections to player names + internal static readonly Dictionary connNames = new Dictionary(); + + public override void OnStartServer() + { + connNames.Clear(); + } + + public override void OnStartClient() + { + chatHistory.text = ""; + } + + [Command(requiresAuthority = false)] + void CmdSend(string message, NetworkConnectionToClient sender = null) + { + if (!connNames.ContainsKey(sender)) + connNames.Add(sender, sender.identity.GetComponent().playerName); + + if (!string.IsNullOrWhiteSpace(message)) + RpcReceive(connNames[sender], message.Trim()); + } + + [ClientRpc] + void RpcReceive(string playerName, string message) + { + string prettyMessage = playerName == localPlayerName ? + $"{playerName}: {message}" : + $"{playerName}: {message}"; + AppendMessage(prettyMessage); + } + + void AppendMessage(string message) + { + StartCoroutine(AppendAndScroll(message)); + } + + IEnumerator AppendAndScroll(string message) + { + chatHistory.text += message + "\n"; + + // it takes 2 frames for the UI to update ?!?! + yield return null; + yield return null; + + // slam the scrollbar down + scrollbar.value = 0; + } + + // Called by UI element ExitButton.OnClick + public void ExitButtonOnClick() + { + // StopHost calls both StopClient and StopServer + // StopServer does nothing on remote clients + NetworkManager.singleton.StopHost(); + } + + // Called by UI element MessageField.OnValueChanged + public void ToggleButton(string input) + { + sendButton.interactable = !string.IsNullOrWhiteSpace(input); + } + + // Called by UI element MessageField.OnEndEdit + public void OnEndEdit(string input) + { + if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter) || Input.GetButtonDown("Submit")) + SendMessage(); + } + + // Called by OnEndEdit above and UI element SendButton.OnClick + public void SendMessage() + { + if (!string.IsNullOrWhiteSpace(chatMessage.text)) + { + CmdSend(chatMessage.text.Trim()); + chatMessage.text = string.Empty; + chatMessage.ActivateInputField(); + } + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta new file mode 100644 index 0000000..1f5d605 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2c102f62d739545269250f48327d4429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scripts/ChatUI.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs new file mode 100644 index 0000000..a84e3da --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs @@ -0,0 +1,52 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.Chat +{ + public class LoginUI : MonoBehaviour + { + [Header("UI Elements")] + [SerializeField] internal InputField networkAddressInput; + [SerializeField] internal InputField usernameInput; + [SerializeField] internal Button hostButton; + [SerializeField] internal Button clientButton; + [SerializeField] internal Text errorText; + + public static LoginUI instance; + + string originalNetworkAddress; + + void Awake() + { + instance = this; + } + + void Start() + { + // if we don't have a networkAddress, set a default one. + if (string.IsNullOrWhiteSpace(NetworkManager.singleton.networkAddress)) + NetworkManager.singleton.networkAddress = "localhost"; + + // cache the original networkAddress for resetting if blank. + originalNetworkAddress = NetworkManager.singleton.networkAddress; + } + + void Update() + { + // bidirectional sync of networkAddressInput and NetworkManager.networkAddress + // Order of operations is important here...Don't switch the order of these steps. + if (string.IsNullOrWhiteSpace(NetworkManager.singleton.networkAddress)) + NetworkManager.singleton.networkAddress = originalNetworkAddress; + + if (networkAddressInput.text != NetworkManager.singleton.networkAddress) + networkAddressInput.text = NetworkManager.singleton.networkAddress; + } + + // Called by UI element UsernameInput.OnValueChanged + public void ToggleButtons(string username) + { + hostButton.interactable = !string.IsNullOrWhiteSpace(username); + clientButton.interactable = !string.IsNullOrWhiteSpace(username); + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta new file mode 100644 index 0000000..ce6801f --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 7a77ca56c9d91af4b81b73a9907d6112 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scripts/LoginUI.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Chat/Scripts/Player.cs b/Assets/Mirror/Examples/Chat/Scripts/Player.cs new file mode 100644 index 0000000..e487757 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/Player.cs @@ -0,0 +1,18 @@ +namespace Mirror.Examples.Chat +{ + public class Player : NetworkBehaviour + { + [SyncVar] + public string playerName; + + public override void OnStartServer() + { + playerName = (string)connectionToClient.authenticationData; + } + + public override void OnStartLocalPlayer() + { + ChatUI.localPlayerName = playerName; + } + } +} diff --git a/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta b/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta new file mode 100644 index 0000000..7b901e5 --- /dev/null +++ b/Assets/Mirror/Examples/Chat/Scripts/Player.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3addc5ad220944ed6888319897606739 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Chat/Scripts/Player.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop.meta b/Assets/Mirror/Examples/CouchCoop.meta new file mode 100644 index 0000000..b38f84d --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f95dee495668d49e6a3930a0de585ef3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/CouchCoop/Materials.meta b/Assets/Mirror/Examples/CouchCoop/Materials.meta new file mode 100644 index 0000000..fa778b1 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0d17118b2ce14576bd5dfc54dc7c1c5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat new file mode 100644 index 0000000..197859b --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialColliders + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 20, y: 20} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 20, y: 20} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0, g: 0.12074661, b: 1, a: 0.1254902} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat.meta b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat.meta new file mode 100644 index 0000000..f8af804 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: ff8e460bc150b4fd2a6a41c94d7ef532 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Materials/MaterialColliders.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat new file mode 100644 index 0000000..cc37324 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialGround + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 30, y: 30} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: bcc8fc05f1f924531a65f39394c0b703, type: 3} + m_Scale: {x: 30, y: 30} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat.meta b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat.meta new file mode 100644 index 0000000..9ba7667 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 037d7d103792c4a6aa3ed9e8f1fd9706 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Materials/MaterialGround.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat new file mode 100644 index 0000000..da1274c --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialPlatform1 + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 10, y: 2} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: bcc8fc05f1f924531a65f39394c0b703, type: 3} + m_Scale: {x: 10, y: 2} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat.meta b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat.meta new file mode 100644 index 0000000..75eaa99 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 0525145f52aa54b7f80b86ebdc7319de +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform1.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat new file mode 100644 index 0000000..f4cea93 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialPlatform2 + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: bcc8fc05f1f924531a65f39394c0b703, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat.meta b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat.meta new file mode 100644 index 0000000..159a246 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlatform2.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat new file mode 100644 index 0000000..a51eee9 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaterialPlayer + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: + - _GLOSSYREFLECTIONS_OFF + - _SPECULARHIGHLIGHTS_OFF + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.5188679, g: 0.5188679, b: 0.5188679, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat.meta b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat.meta new file mode 100644 index 0000000..465792c --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 9b77d86bd031f46efa8887f0c4e8d79f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Materials/MaterialPlayer.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity b/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity new file mode 100644 index 0000000..1eca571 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity @@ -0,0 +1,3630 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &34377703 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 34377704} + - component: {fileID: 34377707} + - component: {fileID: 34377706} + - component: {fileID: 34377705} + m_Layer: 0 + m_Name: Collider (2) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &34377704 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34377703} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 4, z: 10} + m_LocalScale: {x: 40, y: 10, z: 0.01} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &34377705 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34377703} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &34377706 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34377703} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &34377707 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 34377703} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &80415366 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 80415367} + - component: {fileID: 80415370} + - component: {fileID: 80415369} + - component: {fileID: 80415368} + m_Layer: 0 + m_Name: Platform (6) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &80415367 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 80415366} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 7.49, y: 1.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &80415368 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 80415366} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &80415369 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 80415366} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &80415370 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 80415366} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936778} + - component: {fileID: 88936779} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.38823533, g: 0.34901962, b: 0.30588236, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 7 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.2164396, y: 0, z: 0, w: 0.97629607} + m_LocalPosition: {x: 0, y: 6.7, z: -10.4} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 25, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!114 &88936779 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73edff93783204b298f805477ae30ecd, type: 3} + m_Name: + m_EditorClassIdentifier: + cameraTransform: {fileID: 88936777} + camSpeed: 2 + orthoSizeSpeed: 2 + mainCamera: {fileID: 88936776} + cameraZ: -5 + cameraBufferX: 0.1 + cameraBufferY: 0.1 + minOrthographicSize: 0.1 + targetYPosition: 4.5 +--- !u!1 &119916132 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 119916133} + m_Layer: 0 + m_Name: Platform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &119916133 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 119916132} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -4.66, y: 2.59, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1218169079} + - {fileID: 1745218773} + m_Father: {fileID: 1641741935} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &121552833 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 121552834} + - component: {fileID: 121552837} + - component: {fileID: 121552836} + - component: {fileID: 121552835} + m_Layer: 0 + m_Name: Platform (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &121552834 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121552833} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5.972, y: 2.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &121552835 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121552833} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &121552836 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121552833} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &121552837 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 121552833} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &187966239 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 187966240} + m_Layer: 0 + m_Name: Platform Target + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &187966240 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 187966239} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 2.52, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1515892990} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &335647023 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 335647024} + m_Layer: 0 + m_Name: Colliders + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &335647024 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 335647023} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 828682886} + - {fileID: 446496353} + - {fileID: 34377704} + - {fileID: 1179387012} + - {fileID: 498523323} + - {fileID: 1263590060} + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &388677686 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 388677690} + - component: {fileID: 388677689} + - component: {fileID: 388677688} + - component: {fileID: 388677687} + m_Layer: 0 + m_Name: Platform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &388677687 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388677686} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 0.5, z: 1} + m_Center: {x: 0, y: 0.25, z: 0} +--- !u!23 &388677688 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388677686} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 0525145f52aa54b7f80b86ebdc7319de, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &388677689 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388677686} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &388677690 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388677686} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 20, y: 2, z: 5} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &437386904 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 437386905} + - component: {fileID: 437386906} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &437386905 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 437386904} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 5, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &437386906 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 437386904} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &446496352 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 446496353} + - component: {fileID: 446496356} + - component: {fileID: 446496355} + - component: {fileID: 446496354} + m_Layer: 0 + m_Name: Collider (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &446496353 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 446496352} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 4, z: -10} + m_LocalScale: {x: 40, y: 10, z: 0.01} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &446496354 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 446496352} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &446496355 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 446496352} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &446496356 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 446496352} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &472126870 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 472126871} + - component: {fileID: 472126872} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &472126871 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 472126870} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &472126872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 472126870} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &498523322 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 498523323} + - component: {fileID: 498523326} + - component: {fileID: 498523325} + - component: {fileID: 498523324} + m_Layer: 0 + m_Name: Collider (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &498523323 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498523322} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -20, y: 4, z: 0} + m_LocalScale: {x: 20, y: 10, z: 0.01} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!65 &498523324 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498523322} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &498523325 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498523322} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &498523326 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498523322} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &605740505 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 605740506} + - component: {fileID: 605740507} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &605740506 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 605740505} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &605740507 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 605740505} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &655358419 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 655358420} + - component: {fileID: 655358423} + - component: {fileID: 655358422} + - component: {fileID: 655358421} + m_Layer: 5 + m_Name: Button RemovePlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &655358420 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 655358419} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1420928155} + m_Father: {fileID: 1324361701} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 131.5, y: 53} + m_SizeDelta: {x: 120, y: 40} + m_Pivot: {x: 0, y: 0.5} +--- !u!114 &655358421 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 655358419} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.2735849, g: 0.2735849, b: 0.2735849, a: 1} + m_SelectedColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 655358422} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &655358422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 655358419} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &655358423 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 655358419} + m_CullTransparentMesh: 1 +--- !u!1 &738449925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 738449926} + - component: {fileID: 738449929} + - component: {fileID: 738449928} + - component: {fileID: 738449927} + m_Layer: 0 + m_Name: Platform (4) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &738449926 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738449925} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5.38, y: 1.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &738449927 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738449925} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &738449928 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738449925} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &738449929 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738449925} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &778458459 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 778458460} + - component: {fileID: 778458461} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &778458460 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 778458459} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -6, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &778458461 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 778458459} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &828682885 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 828682886} + - component: {fileID: 828682889} + - component: {fileID: 828682888} + - component: {fileID: 828682887} + m_Layer: 0 + m_Name: Collider + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &828682886 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 828682885} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 22.4} + m_LocalScale: {x: 100, y: 0.01, z: 100} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &828682887 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 828682885} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &828682888 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 828682885} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &828682889 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 828682885} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &898358220 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 898358221} + - component: {fileID: 898358224} + - component: {fileID: 898358223} + - component: {fileID: 898358222} + m_Layer: 0 + m_Name: Platform (8) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &898358221 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898358220} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 6.42, y: 1.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &898358222 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898358220} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &898358223 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898358220} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &898358224 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898358220} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1036234661 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1036234662} + m_Layer: 0 + m_Name: Platform Target + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1036234662 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1036234661} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 5.22, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1587167464} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1107091652 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1107091656} + - component: {fileID: 1107091655} + - component: {fileID: 1107091653} + m_Layer: 0 + m_Name: Ground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1107091653 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 037d7d103792c4a6aa3ed9e8f1fd9706, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1107091655 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1107091656 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 21.8} + m_LocalScale: {x: 10, y: 1, z: 10} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1111626353 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1111626354} + - component: {fileID: 1111626356} + - component: {fileID: 1111626355} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1111626354 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1111626353} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1324361701} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 5.0000005, y: -21.902702} + m_SizeDelta: {x: 506.5, y: 98.6196} + m_Pivot: {x: 0, y: 0.5} +--- !u!114 &1111626355 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1111626353} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: 'Adding players requires controls setup for that X player. + + 4 have + been setup for you + + See CouchPlayerManager for controls and to add more.' +--- !u!222 &1111626356 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1111626353} + m_CullTransparentMesh: 1 +--- !u!1 &1179387011 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1179387012} + - component: {fileID: 1179387015} + - component: {fileID: 1179387014} + - component: {fileID: 1179387013} + m_Layer: 0 + m_Name: Collider (3) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1179387012 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179387011} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 20, y: 4, z: 0} + m_LocalScale: {x: 20, y: 10, z: 0.01} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!65 &1179387013 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179387011} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1179387014 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179387011} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1179387015 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1179387011} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1218169078 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1218169079} + - component: {fileID: 1218169084} + - component: {fileID: 1218169083} + - component: {fileID: 1218169082} + - component: {fileID: 1218169081} + - component: {fileID: 1218169080} + m_Layer: 0 + m_Name: Platform (2) + m_TagString: Finish + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1218169079 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 119916133} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1218169080 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6c2bc1b05e6794a419ce8e1091f59a05, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + endTarget: {fileID: 1745218773} + moveSpeed: 0.5 + moveObj: 0 + moveStopsUponExit: 0 + moveStartsUponCollision: 1 +--- !u!114 &1218169081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 1210565816 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!65 &1218169082 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1218169083 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1218169084 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1218169078} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1263590059 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1263590060} + - component: {fileID: 1263590063} + - component: {fileID: 1263590062} + - component: {fileID: 1263590061} + m_Layer: 0 + m_Name: Collider (5) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1263590060 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1263590059} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 9, z: 0} + m_LocalScale: {x: 40, y: 0.01, z: 20} + m_Children: [] + m_Father: {fileID: 335647024} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1263590061 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1263590059} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1263590062 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1263590059} + m_Enabled: 0 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: ff8e460bc150b4fd2a6a41c94d7ef532, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1263590063 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1263590059} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1284305744 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1284305745} + m_Layer: 0 + m_Name: PlatformsStationary + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1284305745 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284305744} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1107091656} + - {fileID: 388677690} + - {fileID: 738449926} + - {fileID: 121552834} + - {fileID: 80415367} + - {fileID: 1648326109} + - {fileID: 898358221} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1284513249 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1284513250} + - component: {fileID: 1284513255} + - component: {fileID: 1284513254} + - component: {fileID: 1284513253} + - component: {fileID: 1284513252} + - component: {fileID: 1284513251} + m_Layer: 0 + m_Name: Platform (1) + m_TagString: Finish + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1284513250 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1515892990} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1284513251 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6c2bc1b05e6794a419ce8e1091f59a05, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + endTarget: {fileID: 187966240} + moveSpeed: 0.3 + moveObj: 1 + moveStopsUponExit: 0 + moveStartsUponCollision: 0 +--- !u!114 &1284513252 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 3339509378 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!65 &1284513253 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1284513254 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1284513255 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1284513249} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1305041271 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1305041272} + - component: {fileID: 1305041273} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1305041272 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305041271} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1305041273 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305041271} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1324361700 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1324361701} + - component: {fileID: 1324361703} + - component: {fileID: 1324361702} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1324361701 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1324361700} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1111626354} + - {fileID: 1844416208} + - {fileID: 655358420} + m_Father: {fileID: 1691128381} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 5.6762695, y: 6.8380127} + m_SizeDelta: {x: 251.8043, y: 149.5285} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1324361702 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1324361700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 0.0627451} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1324361703 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1324361700} + m_CullTransparentMesh: 1 +--- !u!1 &1372141312 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1372141313} + - component: {fileID: 1372141314} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1372141313 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1372141312} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 6, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1372141314 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1372141312} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1420928154 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1420928155} + - component: {fileID: 1420928157} + - component: {fileID: 1420928156} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1420928155 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1420928154} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 655358420} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1420928156 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1420928154} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Remove +--- !u!222 &1420928157 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1420928154} + m_CullTransparentMesh: 1 +--- !u!1 &1515892989 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1515892990} + m_Layer: 0 + m_Name: Platform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1515892990 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1515892989} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -3.55, y: 1.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1284513250} + - {fileID: 187966240} + m_Father: {fileID: 1641741935} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1562669729 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1562669730} + - component: {fileID: 1562669731} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &1562669730 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562669729} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -5, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1562669731 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1562669729} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1587167463 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1587167464} + m_Layer: 0 + m_Name: Platform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1587167464 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1587167463} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -5.81, y: 3.64, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2105958120} + - {fileID: 1036234662} + m_Father: {fileID: 1641741935} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1641741934 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1641741935} + m_Layer: 0 + m_Name: PlatformsMoving + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1641741935 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1641741934} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1515892990} + - {fileID: 119916133} + - {fileID: 1587167464} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1648326108 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1648326109} + - component: {fileID: 1648326112} + - component: {fileID: 1648326111} + - component: {fileID: 1648326110} + m_Layer: 0 + m_Name: Platform (7) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1648326109 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1648326108} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 4.3, y: 1.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1284305745} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &1648326110 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1648326108} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1648326111 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1648326108} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1648326112 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1648326108} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1691128377 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1691128381} + - component: {fileID: 1691128380} + - component: {fileID: 1691128379} + - component: {fileID: 1691128378} + - component: {fileID: 1691128382} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1691128378 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1691128377} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1691128379 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1691128377} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1280, y: 800} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &1691128380 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1691128377} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1691128381 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1691128377} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1324361701} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1691128382 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1691128377} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8b76e63e8ad5c42d59aa6ccdda8cddbf, type: 3} + m_Name: + m_EditorClassIdentifier: + couchPlayerManager: {fileID: 0} + buttonAddPlayer: {fileID: 1844416209} + buttonRemovePlayer: {fileID: 655358421} +--- !u!1 &1745218772 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1745218773} + m_Layer: 0 + m_Name: Platform Target + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1745218773 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1745218772} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 3.81, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 119916133} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1844416207 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1844416208} + - component: {fileID: 1844416211} + - component: {fileID: 1844416210} + - component: {fileID: 1844416209} + m_Layer: 5 + m_Name: Button AddPlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1844416208 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1844416207} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1922846804} + m_Father: {fileID: 1324361701} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 5, y: 53} + m_SizeDelta: {x: 120, y: 40} + m_Pivot: {x: 0, y: 0.5} +--- !u!114 &1844416209 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1844416207} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_HighlightedColor: {r: 0, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.2735849, g: 0.2735849, b: 0.2735849, a: 1} + m_SelectedColor: {r: 0.27058825, g: 0.27058825, b: 0.27058825, a: 1} + m_DisabledColor: {r: 0, g: 0, b: 0, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1844416210} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1844416210 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1844416207} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1844416211 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1844416207} + m_CullTransparentMesh: 1 +--- !u!1 &1922846803 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1922846804} + - component: {fileID: 1922846806} + - component: {fileID: 1922846805} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1922846804 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1922846803} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1844416208} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1922846805 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1922846803} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Add Player +--- !u!222 &1922846806 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1922846803} + m_CullTransparentMesh: 1 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.39044833, y: -0.34682897, z: 0.161729, w: 0.8373192} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 50, y: -45, z: 0} +--- !u!1 &2103688474 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2103688475} + - component: {fileID: 2103688476} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &2103688475 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2103688474} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -4, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2103688476 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2103688474} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2105958119 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2105958120} + - component: {fileID: 2105958125} + - component: {fileID: 2105958124} + - component: {fileID: 2105958123} + - component: {fileID: 2105958122} + - component: {fileID: 2105958121} + m_Layer: 0 + m_Name: Platform (3) + m_TagString: Finish + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2105958120 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1587167464} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2105958121 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6c2bc1b05e6794a419ce8e1091f59a05, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + endTarget: {fileID: 1036234662} + moveSpeed: 0.8 + moveObj: 0 + moveStopsUponExit: 1 + moveStartsUponCollision: 1 +--- !u!114 &2105958122 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 1365075721 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!65 &2105958123 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &2105958124 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 1058f0fbda1e84e6c9e18b7ebf1d0c4b, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &2105958125 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105958119} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &2816348668128435081 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2816348668128435083} + - component: {fileID: 2816348668128435086} + - component: {fileID: 2816348668128435085} + - component: {fileID: 2816348668128435084} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &2816348668128435083 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2816348668128435081} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2816348668128435084 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2816348668128435081} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &2816348668128435085 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2816348668128435081} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &2816348668128435086 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2816348668128435081} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 2816348668128435085} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 4305101904764985729, guid: 44329fdf23cc043648529f3cb0a8fd7c, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 8872462076811691049, guid: c5eb745ce31f9439f9bb3fe7c091ad27, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 +--- !u!1 &4239341308390436545 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4239341308390436546} + - component: {fileID: 4239341308390436547} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4239341308390436546 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341308390436545} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4239341308390436547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341308390436545} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &4239341308987619385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4239341308987619386} + - component: {fileID: 4239341308987619387} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4239341308987619386 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341308987619385} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4239341308987619387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341308987619385} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &4239341309125333740 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4239341309125333741} + - component: {fileID: 4239341309125333742} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4239341309125333741 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341309125333740} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4239341309125333742 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341309125333740} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &4239341309712137293 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4239341309712137294} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4239341309712137294 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341309712137293} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 6, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4239341308390436546} + - {fileID: 4239341310108531884} + - {fileID: 4239341309125333741} + - {fileID: 4239341308987619386} + - {fileID: 605740506} + - {fileID: 472126871} + - {fileID: 1305041272} + - {fileID: 2103688475} + - {fileID: 1562669730} + - {fileID: 437386905} + - {fileID: 1372141313} + - {fileID: 778458460} + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &4239341310108531883 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4239341310108531884} + - component: {fileID: 4239341310108531885} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4239341310108531884 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341310108531883} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4239341309712137294} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4239341310108531885 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4239341310108531883} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &5746453777584925833 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5746453777584925836} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5746453777584925834 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5746453777584925836} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!114 &5746453777584925835 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5746453777584925836} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!1 &5746453777584925836 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5746453777584925833} + - component: {fileID: 5746453777584925834} + - component: {fileID: 5746453777584925835} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 diff --git a/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity.meta b/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity.meta new file mode 100644 index 0000000..9c962ef --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 639ffa9af490c4a8fb41de76fd1ab4e1 +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/MirrorCouchCoop.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Prefabs.meta b/Assets/Mirror/Examples/CouchCoop/Prefabs.meta new file mode 100644 index 0000000..604c473 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 211bc7f1e19a541b69823d0aae4f6c77 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab new file mode 100644 index 0000000..8f1ed03 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab @@ -0,0 +1,526 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4415124803507263412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9057824595171805708} + - component: {fileID: 662729490405160656} + - component: {fileID: 3624570427921084598} + m_Layer: 8 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &9057824595171805708 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3254954141432383832} + m_Father: {fileID: 5328458565928408179} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &662729490405160656 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3624570427921084598 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4415124803507263412} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9b77d86bd031f46efa8887f0c4e8d79f, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &5744931112379996478 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4305313394997208315} + - component: {fileID: 8965569245488384288} + - component: {fileID: 7000040794664630560} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4305313394997208315 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5744931112379996478} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.01, y: 0.01, z: 0.01} + m_Children: [] + m_Father: {fileID: 4980237708977737702} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.0000098199, y: 1.433} + m_SizeDelta: {x: 500, y: 213.418} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8965569245488384288 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5744931112379996478} + m_CullTransparentMesh: 1 +--- !u!114 &7000040794664630560 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5744931112379996478} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 1 + m_MinSize: 10 + m_MaxSize: 113 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: '0 + + Player' +--- !u!1 &5808292118690144754 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4980237708977737702} + - component: {fileID: 6744980396040549407} + - component: {fileID: 2707953842156002887} + - component: {fileID: 509779290406182369} + - component: {fileID: 3756035243087774342} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4980237708977737702 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5808292118690144754} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4305313394997208315} + m_Father: {fileID: 5328458565928408179} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 1} + m_SizeDelta: {x: 5, y: 5} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!223 &6744980396040549407 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5808292118690144754} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &2707953842156002887 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5808292118690144754} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &509779290406182369 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5808292118690144754} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &3756035243087774342 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5808292118690144754} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: afa2d590c474413d9fc183551385ed85, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &5815001218983416211 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3254954141432383832} + - component: {fileID: 1800893346221236401} + - component: {fileID: 136369082707552984} + m_Layer: 8 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3254954141432383832 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 9057824595171805708} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1800893346221236401 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &136369082707552984 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5815001218983416211} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &8872462076811691049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5328458565928408179} + - component: {fileID: 8537344390966522168} + - component: {fileID: 887491563423388292} + - component: {fileID: 1143206540915927667} + - component: {fileID: 3175779197224890082} + - component: {fileID: -8083293324570022796} + - component: {fileID: 2898688981306985052} + - component: {fileID: 6286322935166147715} + m_Layer: 0 + m_Name: CouchPlayer + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5328458565928408179 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.4, y: 0.4, z: 0.4} + m_Children: + - {fileID: 9057824595171805708} + - {fileID: 4980237708977737702} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8537344390966522168 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 435478594 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &887491563423388292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 5328458565928408179} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 1 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!136 &1143206540915927667 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &3175779197224890082 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0.1 + m_AngularDrag: 0.1 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 112 + m_CollisionDetection: 0 +--- !u!114 &-8083293324570022796 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1931e6adfa27e41bbbea220a6436c0e9, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + rb: {fileID: 3175779197224890082} + movementSpeed: 3 + jumpSpeed: 6 + couchPlayerManager: {fileID: 0} + playerNumber: 0 + textPlayerNumber: {fileID: 7000040794664630560} +--- !u!114 &2898688981306985052 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &6286322935166147715 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8872462076811691049} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 19882c332836048ada1935c7fb20283b, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 diff --git a/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab.meta b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab.meta new file mode 100644 index 0000000..2131c8b --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c5eb745ce31f9439f9bb3fe7c091ad27 +PrefabImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayer.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab new file mode 100644 index 0000000..3eb1285 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab @@ -0,0 +1,73 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4305101904764985729 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4456829670910880163} + - component: {fileID: 2502210482294623506} + - component: {fileID: 6157389571773585229} + m_Layer: 0 + m_Name: CouchPlayerManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4456829670910880163 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4305101904764985729} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2502210482294623506 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4305101904764985729} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 4177435541 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &6157389571773585229 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4305101904764985729} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 32f263c662d1e4d33870c9411461bbd0, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + canvasScript: {fileID: 0} + playerPrefabs: + - {fileID: 8872462076811691049, guid: c5eb745ce31f9439f9bb3fe7c091ad27, type: 3} + totalCouchPlayers: 0 + playerKeyJump: 0000000031000000320000003300000034000000 + playerKeyLeft: 000000006100000066000000680000006b000000 + playerKeyRight: 0000000064000000670000006a0000006c000000 diff --git a/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab.meta b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab.meta new file mode 100644 index 0000000..689ee3f --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 44329fdf23cc043648529f3cb0a8fd7c +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Prefabs/CouchPlayerManager.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts.meta b/Assets/Mirror/Examples/CouchCoop/Scripts.meta new file mode 100644 index 0000000..328f435 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d69e8ccc667f4946889e0ab1e09357e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: '' + assetBundleName: '' + assetBundleVariant: '' diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs new file mode 100644 index 0000000..5e2579c --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs @@ -0,0 +1,73 @@ +using UnityEngine; +namespace Mirror.Examples.CouchCoop +{ + public class CameraViewForAll : MonoBehaviour + { + public Transform cameraTransform; + public float camSpeed = 2.0f; + public float orthoSizeSpeed = 2.0f; + public Camera mainCamera; + public float cameraZ = -5; + + public float cameraBufferX = 0.1f; + public float cameraBufferY = 0.1f; + public float minOrthographicSize = 0.1f; + public float targetYPosition = 4.5f; // Optional Y position if cameras rotated + + private Vector2Int boundsMin; + private Vector2Int boundsMax; + private Vector3 targetCameraPosition; + private float targetOrthographicSize; + + private void Update() + { + if (CouchPlayer.playersList.Count > 0) + { + CalculateBounds(); + CalculateTargetCameraPosAndSize(); + MoveCamera(); + } + } + + private void CalculateBounds() + { + boundsMin = new Vector2Int(int.MaxValue, int.MaxValue); + boundsMax = new Vector2Int(int.MinValue, int.MinValue); + + foreach (GameObject player in CouchPlayer.playersList) + { + Vector3 playerPosition = player.transform.position; + boundsMin.x = Mathf.Min(boundsMin.x, Mathf.FloorToInt(playerPosition.x)); + boundsMin.y = Mathf.Min(boundsMin.y, Mathf.FloorToInt(playerPosition.y)); + boundsMax.x = Mathf.Max(boundsMax.x, Mathf.CeilToInt(playerPosition.x)); + boundsMax.y = Mathf.Max(boundsMax.y, Mathf.CeilToInt(playerPosition.y)); + } + + boundsMin.x -= Mathf.FloorToInt(cameraBufferX); + boundsMin.y -= Mathf.FloorToInt(cameraBufferY); + boundsMax.x += Mathf.CeilToInt(cameraBufferX); + boundsMax.y += Mathf.CeilToInt(cameraBufferY); + } + + private void CalculateTargetCameraPosAndSize() + { + float aspectRatio = (float)Screen.width / Screen.height; + + float requiredOrthographicSizeX = Mathf.Max((boundsMax.x - boundsMin.x) / 2 / aspectRatio, minOrthographicSize / aspectRatio); + float requiredOrthographicSizeY = Mathf.Max(boundsMax.y - boundsMin.y / 2, minOrthographicSize); + + targetOrthographicSize = Mathf.Max(requiredOrthographicSizeX, requiredOrthographicSizeY); + + float cameraX = (boundsMax.x + boundsMin.x) / 2; + float cameraY = targetYPosition != 0.0f ? targetYPosition : (boundsMax.y + boundsMin.y) / 2; + + targetCameraPosition = new Vector3(cameraX, cameraY, cameraZ); + } + + private void MoveCamera() + { + cameraTransform.position = Vector3.Lerp(cameraTransform.position, targetCameraPosition, camSpeed * Time.deltaTime); + mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, targetOrthographicSize, orthoSizeSpeed * Time.deltaTime); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs.meta new file mode 100644 index 0000000..8ad0c15 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 73edff93783204b298f805477ae30ecd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs new file mode 100644 index 0000000..ff338ce --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs @@ -0,0 +1,32 @@ +using UnityEngine; +using UnityEngine.UI; +namespace Mirror.Examples.CouchCoop +{ + public class CanvasScript : MonoBehaviour + { + public CouchPlayerManager couchPlayerManager; // Sets itself + public Button buttonAddPlayer, buttonRemovePlayer; // Make sure to attach these Buttons in the Inspector + + private void Start() + { + buttonAddPlayer.onClick.AddListener(ButtonAddPlayer); + buttonRemovePlayer.onClick.AddListener(ButtonRemovePlayer); + } + + private void ButtonAddPlayer() + { + if (couchPlayerManager == null) + { Debug.Log("Start game first."); return; } + + couchPlayerManager.CmdAddPlayer(); + } + + private void ButtonRemovePlayer() + { + if (couchPlayerManager == null) + { Debug.Log("Start game first."); return; } + + couchPlayerManager.CmdRemovePlayer(); + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs.meta new file mode 100644 index 0000000..e85926c --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8b76e63e8ad5c42d59aa6ccdda8cddbf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs new file mode 100644 index 0000000..3964a4e --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.CouchCoop +{ + public class CouchPlayer : NetworkBehaviour + { + public Rigidbody rb; + public float movementSpeed = 3; + public float jumpSpeed = 6; + private float movementVelocity; + private bool isGrounded; + + public CouchPlayerManager couchPlayerManager; + private KeyCode jumpKey = KeyCode.Space; // Check CouchPlayerManager for controls + private KeyCode leftKey = KeyCode.LeftArrow; + private KeyCode rightKey = KeyCode.RightArrow; + + [SyncVar(hook = nameof(OnNumberChangedHook))] + public int playerNumber = 0; + public Text textPlayerNumber; + + // a list of players, is used for camera + public readonly static List playersList = new List(); + + public void Start() + { + playersList.Add(this.gameObject); + // print("playersList: " + playersList.Count); + + SetPlayerUI(); + } + + public void OnDestroy() + { + playersList.Remove(this.gameObject); + // print("playersList: " + playersList.Count); + } + + public override void OnStartAuthority() + { + this.enabled = true; + + if (isOwned) + { +#if UNITY_2022_2_OR_NEWER + couchPlayerManager = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + couchPlayerManager = GameObject.FindObjectOfType(); +#endif + // setup controls according to the pre-sets on CouchPlayerManager + jumpKey = couchPlayerManager.playerKeyJump[playerNumber]; + leftKey = couchPlayerManager.playerKeyLeft[playerNumber]; + rightKey = couchPlayerManager.playerKeyRight[playerNumber]; + } + } + + void Update() + { + if (!Application.isFocused) return; + if (isOwned == false) { return; } + + // you can control all local players via arrow keys and space bar for fun testing + // otherwise check and set individual controls in CouchPlayerManager script. + if (isGrounded == true) + { + if (Input.GetKey(KeyCode.Space) || Input.GetKeyDown(jumpKey)) + { +#if UNITY_6000_0_OR_NEWER + rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpSpeed); +#else + rb.velocity = new Vector2(rb.velocity.x, jumpSpeed); +#endif + } + } + + movementVelocity = 0; + + if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(leftKey)) + { + movementVelocity = -movementSpeed; + } + if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(rightKey)) + { + movementVelocity = movementSpeed; + } +#if UNITY_6000_0_OR_NEWER + rb.linearVelocity = new Vector2(movementVelocity, rb.linearVelocity.y); +#else + rb.velocity = new Vector2(movementVelocity, rb.velocity.y); +#endif + } + + [ClientCallback] + void OnCollisionExit(Collision col) + { + if (isOwned == false) { return; } + isGrounded = false; + } + + [ClientCallback] + void OnCollisionStay(Collision col) + { + if (isOwned == false) { return; } + isGrounded = true; + } + + void OnNumberChangedHook(int _old, int _new) + { + //Debug.Log(name + " - OnNumberChangedHook: " + playerNumber); + SetPlayerUI(); + } + + public void SetPlayerUI() + { + // called from hook and in start, to solve a race condition + if (isOwned) + { + textPlayerNumber.text = "Local: " + playerNumber; + } + else + { + textPlayerNumber.text = "Remote: " + playerNumber; + } + } + } +} diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs.meta new file mode 100644 index 0000000..8d7caba --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 1931e6adfa27e41bbbea220a6436c0e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: '' + assetBundleName: '' + assetBundleVariant: '' +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs new file mode 100644 index 0000000..d652048 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs @@ -0,0 +1,69 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.CouchCoop +{ + public class CouchPlayerManager : NetworkBehaviour + { + // reference to UI that should be in the scene + public CanvasScript canvasScript; + // for multiple player prefabs, currently not implemented, remember to add these into Network Managers Prefab array. + public GameObject[] playerPrefabs; + public int totalCouchPlayers = 0; + + // ignore key controls 0, we will always start at 1 + public KeyCode[] playerKeyJump; + public KeyCode[] playerKeyLeft; + public KeyCode[] playerKeyRight; + + // store a list of players so we know which to remove later + // can be non sync-list, but may be useful for future features + readonly SyncList couchPlayersList = new SyncList(); + + public override void OnStartAuthority() + { + // hook up UI to local player, for cmd communication +#if UNITY_2022_2_OR_NEWER + canvasScript = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + canvasScript = GameObject.FindObjectOfType(); +#endif + canvasScript.couchPlayerManager = this; + } + + [Command] + public void CmdAddPlayer() + { + if (totalCouchPlayers >= playerKeyJump.Length-1) + { + Debug.Log(name + " - No controls setup for further players."); + return; + } + + totalCouchPlayers += 1; + Transform spawnObj = NetworkManager.startPositions[Random.Range(0, NetworkManager.startPositions.Count)]; + GameObject playerObj = Instantiate(playerPrefabs[0], spawnObj.position, spawnObj.rotation); + CouchPlayer couchPlayer = playerObj.GetComponent(); + couchPlayer.playerNumber = totalCouchPlayers; + NetworkServer.Spawn(playerObj, connectionToClient); + couchPlayersList.Add(playerObj); + } + + [Command] + public void CmdRemovePlayer() + { + if (totalCouchPlayers <= 0) + { + Debug.Log(name + " - No players to remove for that connection."); + return; + } + + totalCouchPlayers -= 1; + NetworkServer.Destroy(couchPlayersList[couchPlayersList.Count - 1]); + couchPlayersList.RemoveAt(couchPlayersList.Count - 1); + + } + } + +} diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs.meta new file mode 100644 index 0000000..4162bbd --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 32f263c662d1e4d33870c9411461bbd0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs new file mode 100644 index 0000000..32e7e51 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.CouchCoop +{ + public class MovingPlatform : NetworkBehaviour + { + public Transform endTarget; + public float moveSpeed = 0.5f; + // allows for on demand syncing of stopping and starting platform movement, change via server + // note,sync vars changed via inspector do not sync. This is optional feature, can be removed + [SyncVar] + public bool moveObj = true; + + // optional fancy features + public bool moveStopsUponExit = false; + public bool moveStartsUponCollision = false; + + private Vector3 startPosition; + private Vector3 endPosition; + + void Awake() + { + startPosition = transform.position; + endPosition = endTarget.position; + } + + void Update() + { + if (moveObj) + { + float step = moveSpeed * Time.deltaTime; + transform.position = Vector3.MoveTowards(transform.position, endPosition, step); + + if (Vector3.Distance(transform.position, endPosition) < 0.001f) + { + endPosition = endPosition == startPosition ? endTarget.position : startPosition; + if (isServer) + { + RpcResyncPosition(endPosition == startPosition ? (byte)1 : (byte)0); + } + } + } + } + + [ClientRpc] + void RpcResyncPosition(byte _value) + { + //print("RpcResyncPosition: " + _value); + transform.position = _value == 1 ? endTarget.position : startPosition; + } + + // optional + [ServerCallback] + private void OnCollisionEnter(Collision collision) + { + if (moveStartsUponCollision) + { + if (collision.gameObject.tag == "Player") + { + moveObj = true; + } + } + } + + // optional + [ServerCallback] + private void OnCollisionExit(Collision collision) + { + if (moveStopsUponExit) + { + if (collision.gameObject.tag == "Player") + { + moveObj = false; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs.meta new file mode 100644 index 0000000..b4230cf --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 6c2bc1b05e6794a419ce8e1091f59a05 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs b/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs new file mode 100644 index 0000000..a8db1a3 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs @@ -0,0 +1,49 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.CouchCoop +{ + public class PlatformMovement : NetworkBehaviour + { + // A separate script to handle platform behaviour, see its partner script, MovingPlatform.cs + private bool onPlatform; + private Transform platformTransform; + private Vector3 lastPlatformPosition; + + public override void OnStartAuthority() + { + this.enabled = true; + } + + void FixedUpdate() + { + if (onPlatform) + { + Vector3 deltaPosition = platformTransform.position - lastPlatformPosition; + transform.position += deltaPosition; + lastPlatformPosition = platformTransform.position; + } + } + + private void OnCollisionEnter(Collision collision) + { + + if (collision.gameObject.tag == "Finish") + { + platformTransform = collision.gameObject.GetComponent(); + lastPlatformPosition = platformTransform.position; + onPlatform = true; + } + } + + private void OnCollisionExit(Collision collision) + { + // ideally set a Platform tag, but we'l just use a Unity Pre-set. + if (collision.gameObject.tag == "Finish") + { + onPlatform = false; + platformTransform = null; + } + } + } +} diff --git a/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs.meta b/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs.meta new file mode 100644 index 0000000..2a88b85 --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 19882c332836048ada1935c7fb20283b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt b/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt new file mode 100644 index 0000000..cf19eed --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt @@ -0,0 +1,16 @@ +# Couch Co-Op Example + +Open scene: SceneCouchCoop + +- Start game, click UI button Add Player, to add local couch players, add as few or as many local couch players as you want. +(only 4 keyboard inputs have been setup for this example, for more players, add more controls). +Join via another client, localhost, LAN or across internet, and add remote couch players. +(no forced amount, can be any combination, example, 1 vs 1, 2 vs 2, 2 vs 4, 99 vs 20) + +- Jump keys are numbers 1, 2, 3, 4, depending on which player you are. +Then AD, FG, HJ, KL for movement, all can be customised on the CouchPlayerManager script. +Everyone joint uses arrow keys and space bar for quick fun testing of all local couch players. +(something you would remove for release) + +- Locate Prefab: CouchPlayerManager +Set your custom controls here, the max couch players that can be spawned will depend on control key array lengths. \ No newline at end of file diff --git a/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt.meta b/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt.meta new file mode 100644 index 0000000..a0ec9ff --- /dev/null +++ b/Assets/Mirror/Examples/CouchCoop/_ReadMe.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: bd8cfa13483c4428facfd02c63e3dbca +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/CouchCoop/_ReadMe.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Discovery.meta b/Assets/Mirror/Examples/Discovery.meta new file mode 100644 index 0000000..85a73ff --- /dev/null +++ b/Assets/Mirror/Examples/Discovery.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 450d6133608b04c57a6ebd6830d455fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Discovery/Prefabs.meta b/Assets/Mirror/Examples/Discovery/Prefabs.meta new file mode 100644 index 0000000..ef0083d --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d8abc53a4efb4544ad9cb7a44b4840a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab new file mode 100644 index 0000000..9bf56c9 --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9081919128954505657 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8463701767414927392} + - component: {fileID: 435337138507318507} + - component: {fileID: 8589595951595565844} + - component: {fileID: 1410032569926419539} + - component: {fileID: 8188542106662419882} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8463701767414927392 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &435337138507318507 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &8589595951595565844 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1410032569926419539 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 154818596 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!136 &8188542106662419882 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9081919128954505657} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta new file mode 100644 index 0000000..86ec337 --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ecd52c53a6ef7496693343d3e32dace1 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Discovery/Prefabs/Player.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Discovery/Scenes.meta b/Assets/Mirror/Examples/Discovery/Scenes.meta new file mode 100644 index 0000000..ed0ba64 --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ceaf2344f4e6944258442667a9fbbfdf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity b/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity new file mode 100644 index 0000000..7ea11ed --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity @@ -0,0 +1,790 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &62199026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 62199028} + - component: {fileID: 62199027} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &62199027 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62199026} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &62199028 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 62199026} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &441913360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 441913362} + - component: {fileID: 441913361} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &441913361 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441913360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &441913362 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 441913360} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &919124423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 919124425} + - component: {fileID: 919124424} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &919124424 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919124423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &919124425 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 919124423} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.09, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &970214386 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 970214388} + - component: {fileID: 970214387} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &970214387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 970214386} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &970214388 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 970214386} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.99, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1392889995 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1392889998} + - component: {fileID: 1392889997} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &1392889997 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1392889995} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1392889998 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1392889995} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1556883243 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1556883247} + - component: {fileID: 1556883245} + - component: {fileID: 1556883244} + - component: {fileID: 1556883248} + - component: {fileID: 1556883246} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1556883244 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1556883245 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1556883244} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 9081919128954505657, guid: ecd52c53a6ef7496693343d3e32dace1, type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 0 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.009999999776482582 + slowdownSpeed: 0.009999999776482582 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 +--- !u!114 &1556883246 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88c37d3deca7a834d80cfd8d3cfcc510, type: 3} + m_Name: + m_EditorClassIdentifier: + networkDiscovery: {fileID: 1556883248} +--- !u!4 &1556883247 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1556883248 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1556883243} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c761308e733c51245b2e8bb4201f46dc, type: 3} + m_Name: + m_EditorClassIdentifier: + enableActiveDiscovery: 1 + BroadcastAddress: + serverBroadcastListenPort: 47777 + ActiveDiscoveryInterval: 3 + transport: {fileID: 1556883244} + OnServerFound: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1556883246} + m_TargetAssemblyTypeName: Mirror.Discovery.NetworkDiscoveryHUD, Mirror.Components + m_MethodName: OnDiscoveredServer + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + secretHandshake: 1558261479176021378 +--- !u!1 &1611696151 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1611696153} + - component: {fileID: 1611696152} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1611696152 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1611696151} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1611696153 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1611696151} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4.6, y: 0, z: -1.43} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1730851146 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1730851148} + - component: {fileID: 1730851147} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1730851147 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1730851146} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1730851148 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1730851146} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1911023976 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1911023978} + - component: {fileID: 1911023977} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1911023977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911023976} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1911023978 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1911023976} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.78, y: 0, z: -4.03} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1958729888 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1958729890} + - component: {fileID: 1958729889} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1958729889 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1958729888} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1958729890 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1958729888} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4.6, y: 0, z: -4.08} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2054361114 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054361116} + - component: {fileID: 2054361115} + m_Layer: 0 + m_Name: StartPos + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2054361115 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054361114} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &2054361116 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054361114} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.99, y: 0, z: -1.43} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity.meta b/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity.meta new file mode 100644 index 0000000..315e3bd --- /dev/null +++ b/Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 90fddc74fa21c423599167eb28b09dd1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Discovery/Scenes/MirrorDiscovery.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby.meta b/Assets/Mirror/Examples/EdgegapLobby.meta new file mode 100644 index 0000000..2a4478f --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8befc60066f3f148ab1ab4120064045 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.meta b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.meta new file mode 100644 index 0000000..a44b56b --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30978876e2c422c41a7a1bc2b7bb280f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity new file mode 100644 index 0000000..6097228 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity @@ -0,0 +1,1128 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 810426bd131b7fd4dbf1366398224990, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.3420201, y: 0, z: 0, w: 0.9396927} + m_LocalPosition: {x: 0, y: 20, z: -30} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 40, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 150 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 293 +--- !u!1 &531307436 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 531307438} + - component: {fileID: 531307437} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &531307437 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 531307436} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &531307438 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 531307436} + m_LocalRotation: {x: 0, y: -0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: 14, y: 0, z: 14} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: -135, z: 0} +--- !u!1 &542152387 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 542152389} + - component: {fileID: 542152388} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &542152388 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542152387} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &542152389 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542152387} + m_LocalRotation: {x: 0, y: 0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: -14, y: 0, z: 14} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 135, z: 0} +--- !u!1 &542471788 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 542471790} + - component: {fileID: 542471789} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &542471789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542471788} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &542471790 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542471788} + m_LocalRotation: {x: 0, y: -0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: 14, y: 0, z: -14} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0} +--- !u!1 &1018416663 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1018416666} + - component: {fileID: 1018416665} + - component: {fileID: 1018416664} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1018416664 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018416663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1018416665 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018416663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1018416666 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1018416663} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1107091652 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1107091656} + - component: {fileID: 1107091655} + - component: {fileID: 1107091654} + - component: {fileID: 1107091653} + m_Layer: 0 + m_Name: Ground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!23 &1107091653 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 29b49c27a74f145918356859bd7af511, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &1107091654 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &1107091655 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1107091656 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1107091652} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 4, y: 1, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001522} + - component: {fileID: 1282001523} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8aab4c8111b7c411b9b92cf3dbc5bd4e, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 1 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 120 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001523} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 1916082411674582, guid: 6f43bf5488a7443d19ab2a83c6b91f35, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 5890560936853567077, guid: b7dd46dbf38c643f09e206f9fa4be008, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 1 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bc654f29862fc2643b948f772ebb9e68, type: 3} + m_Name: + m_EditorClassIdentifier: + color: {r: 1, g: 1, b: 1, a: 1} + padding: 2 + width: 180 + height: 25 +--- !u!114 &1282001523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fa9d4c3f48a245ed89f122f44e1e81ea, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 294131 + UnreliableMaxMessageSize: 1181 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 + relayAddress: 127.0.0.1 + relayGameServerPort: 8888 + relayGameClientPort: 9999 + relayGUI: 0 + userId: 11111111 + sessionId: 22222222 + lobbyUrl: + lobbyWaitTimeout: 60 +--- !u!1 &1983038232 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1983038234} + - component: {fileID: 1983038233} + m_Layer: 0 + m_Name: Spawn + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1983038233 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1983038232} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1983038234 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1983038232} + m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: -14, y: 0, z: -14} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0} +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.10938167, y: 0.8754261, z: -0.40821788, w: 0.23456976} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 50, y: 150, z: 0} +--- !u!1001 &1813424392215010339 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1813424390365182141, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424390365182141, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391128259723, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391319593378, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391319593378, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391319593378, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391319593378, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391319593378, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391336397939, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391443419299, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391443419299, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 109.51737 + objectReference: {fileID: 0} + - target: {fileID: 1813424391612798255, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391775670328, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391775670328, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391775670328, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391775670328, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424391872098077, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_Pivot.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932097, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392052932157, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_Name + value: LobbyUI + objectReference: {fileID: 0} + - target: {fileID: 1813424392113017367, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392113017367, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392113017367, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392118041961, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392118041961, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392118041961, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392118041961, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392118041961, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392250510888, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392250510888, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392250510888, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392250510888, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392250510888, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392369884078, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 1813424392369884078, guid: ebc1436948da70b4abbf74f58106c318, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: ebc1436948da70b4abbf74f58106c318, type: 3} diff --git a/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity.meta b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity.meta new file mode 100644 index 0000000..4d404fd --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5dbbfee253d4c6e4d915cb88674ec680 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks/NavMesh.asset b/Assets/Mirror/Examples/EdgegapLobby/EdgegapLobbyTanks/NavMesh.asset new file mode 100644 index 0000000000000000000000000000000000000000..f34df8a039bc2d5e28b061db1ff3375bd8f14e67 GIT binary patch literal 6564 zcmbuDU2Ggz702(|Ya2=lacQBU1*R=6ZK1)NI88#^u|{v^Sk$+d(N4;Gizh6+h@$K*NidO;jeGna$$ zA0(TbKfU^RQ&HR3ZJf;^b zSYNJy{O}-W4s*ppJ}UXU0dp`nA0?Me>G)CeFvflh2iLtL#dGEl7<&wM&i^r-Cu1ll z!~S=|K6zOweI@-*lJ~LjM{!O6oc|i~xZfdX^5TCLCi0J`_*f$TYsrgHPI6{E5kGGB zA^+p%9OBdXKat{j(}C?79E|OgDLy9SpM#zGyFP=z;9_ z2G65-tlw=Je23$oAL1hzbv@W!IQD_vj$>yG?}{8`6$XYiLD|565j&GD%%IQMVt{}O*;3w|Da!|^>^aE^c5 z@x2-RkB)P%AI=ZQ|J8BUXqf*KYzJOEIGMZ2V<;!wzqmhK>p0$XW@k|;$JqVxMsV&= z2gu_=p4^`gk{1Vga)10Xc^_l;QF908=KjRJ<(?GJoAW_umoczbG8a3Fl}2Z^kwKmvBs)7}^T?;QM<9 z<|McIox}Xh?_uyO<+n_J8Oq7<`)3yR;r#lToB8GZN62G07$<%ItU3Q*P4VRW=O}p* z%E|Eihwss(|8c1w{j+}e3-_R{-S)a+xP1;F1{1wF_aV3 zCx>UY_kHmY>{p7fLau{x*7zA8>;G_y(`w?g@Xz~uF2%RFClsC z2IDmR{fs&c)i3#eI7Qwcj`5@BUCgcZtEaeqKl~ki`1~}4d(c+6{|?r#33IZ3mTUf6 z8C>(Xmg3g``_BKjQ#|Rvox#;Vzs0v&pZbqdJTLM63;tQZu5c(P+}~fq`*RZ*K&ft@ductUinfNAf?r*1gH6Z-{6sRLV6!-xcDCrc(d9zdb9&6HTS#b$|Vy5KlCfa`hhz@kCQ8SO4D^;)$l> z_tSg$ewadjnD^&|c%rHF`&j)yFT@i~rCk00K!_)rO1b(!E5s8`rTiZF=l$`55KlCf ztPl0M51h}>i$XlnR61VQ_d_9`Xe#Bpz8?wkL{ll(_5E0gCz^`>xxe6l0J1**jvSN| z{!1rU5|ohCu}tjna1LgupS&MqfzmrRWzhur5!B$OUIg> z$Zu8yc5_pmMDLCnxRALUi#<0-{myD(&jE~J%PgIag3jYpPr61y8+){|R~ysX*r$!V zwXt6t2effe8-@PVy}1j$$qT*N3%%(JnBT2`rW@94^Fb7a&6Q3+#-!O_37XN#(`!tU zwCDU<*zMT%(I8w|jcj|q-dYQ6^KdsS z5jN+76%?b?4t&$_n_a(tIH=d>!!v=YYQx%@eX&Q{@T=8s+mC`u-LD1>tTYi@Iaunh z^a8B$3Sl0p`x35QR>NQGm|j!Lxz_505msc@u_K)^QP6JtVbfLGc4fVBBlIsET?pDy zSOsY;9&6TIYo^t0)@VA61qN+2PD>rgY!Ed`EAZO+pIym5;Yb%gtddsrdKTGupLw-z{cWytJ|&yy%o;2B45bU7*f$Z zVD!LUz$Z-hZFBkdQ?>!iNp2ATr%YhHyEo-|eizpZr4wcDef&P4&;^~+ojT{ciH9-g zHlSX2XR~+j^F>;Xxm>(-@s*8B7ccTBp2%?9a@&V(&OU4(s0|xX8UXrCr0OEsBOi`et8r9 zPjPCDgT9zsO1hrb&Nvw_>q!e^V~pCi=YE|TU%yYko+ciT*_X22dK#%Gzo0%?hU=*# z)ECc`ew=cNdg6X}_1r2>#;WmXTSh`@od@q*vhg?{ (EdgegapLobbyKcpTransport)NetworkManager.singleton.transport; + + private void Awake() + { + ValidateName(); + LobbyName.onValueChanged.AddListener(_ => + { + ValidateName(); + }); + CancelButton.onClick.AddListener(() => + { + List.gameObject.SetActive(true); + gameObject.SetActive(false); + }); + SlotSlider.onValueChanged.AddListener(arg0 => + { + SlotCount.text = ((int)arg0).ToString(); + }); + HostButton.onClick.AddListener(() => + { + gameObject.SetActive(false); + _transport.SetServerLobbyParams(LobbyName.text, (int)SlotSlider.value); + NetworkManager.singleton.StartHost(); + }); + ServerButton.onClick.AddListener(() => + { + gameObject.SetActive(false); + _transport.SetServerLobbyParams(LobbyName.text, (int)SlotSlider.value); + NetworkManager.singleton.StartServer(); + }); + } + void ValidateName() + { + bool valid = !string.IsNullOrWhiteSpace(LobbyName.text); + HostButton.interactable = valid; + ServerButton.interactable = valid; + } + } +} diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs.meta b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs.meta new file mode 100644 index 0000000..b0ba48e --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6d48c41753254160ac6a02c9585880f0 +timeCreated: 1709967491 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyCreate.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs new file mode 100644 index 0000000..235b797 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Edgegap; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.EdgegapLobby +{ + public class UILobbyEntry : MonoBehaviour + { + public Button JoinButton; + public Text Name; + public Text PlayerCount; + + private LobbyBrief _lobby; + private UILobbyList _list; + private void Awake() + { + JoinButton.onClick.AddListener(() => + { + _list.Join(_lobby); + }); + } + + public void Init(UILobbyList list, LobbyBrief lobby, bool active = true) + { + gameObject.SetActive(active && lobby.is_joinable); + JoinButton.interactable = lobby.available_slots > 0; + _list = list; + _lobby = lobby; + Name.text = lobby.name; + PlayerCount.text = $"{lobby.player_count}/{lobby.capacity}"; + } + } + +} diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs.meta b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs.meta new file mode 100644 index 0000000..c20313a --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9bd3228b44c0a7e478964d95c512cebf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyEntry.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs new file mode 100644 index 0000000..74a4a3b --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using Edgegap; +using UnityEngine; +using UnityEngine.UI; +namespace Mirror.Examples.EdgegapLobby +{ + public class UILobbyList : MonoBehaviour + { + public UILobbyCreate Create; + + public GameObject EntryPrefab; + public Transform LobbyContent; + public GameObject Loading; + public Button RefreshButton; + public InputField SearchInput; + public Button CreateButton; + public Text Error; + private List _entries = new List(); + + private EdgegapLobbyKcpTransport _transport => (EdgegapLobbyKcpTransport)NetworkManager.singleton.transport; + private void Awake() + { + SearchInput.onValueChanged.AddListener(arg0 => + { + SetLobbies(_transport.Api.Lobbies); + }); + RefreshButton.onClick.AddListener(Refresh); + CreateButton.onClick.AddListener(() => + { + Create.gameObject.SetActive(true); + gameObject.SetActive(false); + }); + } + public void Start() + { + Refresh(); + } + + private void Refresh() + { + Loading.SetActive(true); + _transport.Api.RefreshLobbies(SetLobbies, s => + { + Error.text = s; + Loading.SetActive(false); + }); + } + + public void Join(LobbyBrief lobby) + { + NetworkManager.singleton.networkAddress = lobby.lobby_id; + NetworkManager.singleton.StartClient(); + } + + public void SetLobbies(LobbyBrief[] lobbies) + { + Loading.SetActive(false); + Error.text = ""; + // Create enough entries + for (int i = _entries.Count; i < lobbies.Length; i++) + { + var go = Instantiate(EntryPrefab, LobbyContent); + _entries.Add(go.GetComponent()); + } + + // Update entries + var searchText = SearchInput.text; + for (int i = 0; i < lobbies.Length; i++) + { + _entries[i].Init( + this, + lobbies[i], + // search filter + searchText.Length == 0 || +#if UNITY_2021_3_OR_NEWER + lobbies[i].name.Contains(searchText, StringComparison.InvariantCultureIgnoreCase) +#else + lobbies[i].name.IndexOf(searchText, StringComparison.InvariantCultureIgnoreCase) >= 0 +#endif + ); + } + + // hide entries that are too many + for (int i = lobbies.Length; i < _entries.Count; i++) + { + _entries[i].gameObject.SetActive(false); + } + } + } +} diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs.meta b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs.meta new file mode 100644 index 0000000..92a8a72 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c5e5ad322f314077a66f889b58485188 +timeCreated: 1709962378 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyList.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs new file mode 100644 index 0000000..7567117 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs @@ -0,0 +1,121 @@ +using System; +using Edgegap; +using UnityEngine; +using UnityEngine.UI; +namespace Mirror.Examples.EdgegapLobby +{ + public class UILobbyStatus : MonoBehaviour + { + public GameObject[] ShowDisconnected; + public GameObject[] ShowServer; + public GameObject[] ShowHost; + public GameObject[] ShowClient; + public Button StopServer; + public Button StopHost; + public Button StopClient; + public Text StatusText; + private Status _status; + private EdgegapLobbyKcpTransport _transport; + enum Status + { + Offline, + Server, + Host, + Client + } + void Awake() + { + Refresh(); + StopServer.onClick.AddListener(() => + { + NetworkManager.singleton.StopServer(); + }); + StopHost.onClick.AddListener(() => + { + NetworkManager.singleton.StopHost(); + }); + StopClient.onClick.AddListener(() => + { + NetworkManager.singleton.StopClient(); + }); + } + private void Start() + { + _transport = (EdgegapLobbyKcpTransport)NetworkManager.singleton.transport; + } + private void Update() + { + var status = GetStatus(); + if (_status != status) + { + _status = status; + Refresh(); + } + if (_transport) + { + StatusText.text = _transport.Status.ToString(); + } + else + { + StatusText.text = ""; + } + } + private void Refresh() + { + switch (_status) + { + + case Status.Offline: + SetUI(ShowServer, false); + SetUI(ShowHost, false); + SetUI(ShowClient, false); + SetUI(ShowDisconnected, true); + break; + case Status.Server: + SetUI(ShowDisconnected, false); + SetUI(ShowHost, false); + SetUI(ShowClient, false); + SetUI(ShowServer, true); + break; + case Status.Host: + SetUI(ShowDisconnected, false); + SetUI(ShowServer, false); + SetUI(ShowClient, false); + SetUI(ShowHost, true); + break; + case Status.Client: + SetUI(ShowDisconnected, false); + SetUI(ShowServer, false); + SetUI(ShowHost, false); + SetUI(ShowClient, true); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void SetUI(GameObject[] gos, bool active) + { + foreach (GameObject go in gos) + { + go.SetActive(active); + } + } + private Status GetStatus() + { + if (NetworkServer.active && NetworkClient.active) + { + return Status.Host; + } + if (NetworkServer.active) + { + return Status.Server; + } + if (NetworkClient.active) + { + return Status.Client; + } + return Status.Offline; + } + } +} diff --git a/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs.meta b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs.meta new file mode 100644 index 0000000..bdad317 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 44d2f1170bbe4432bf6f388bcfabefee +timeCreated: 1710138272 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/Scripts/UILobbyStatus.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt b/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt new file mode 100644 index 0000000..25a60e9 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt @@ -0,0 +1,11 @@ +Docs: https://mirror-networking.gitbook.io/docs/manual/examples/edgegap-lobby +This is a copy of the Tanks example (basic scene with player controlled tanks), +but with a lobby ui for using Edgegap's Lobby and Relay service. +It showcases how one might interact with the EdgegapLobbyKcpTransport to list, join and create lobbies. +Providing a good starting point for anyone wanting to use Edgegap lobbies. + +# Setup +As this example uses external services from Edgegap you will need to set up the transport +on the NetworkManager gameobject before you can use it. +Please see the EdgegapLobbyKcpTransport Setup instructions on how to do that: +https://mirror-networking.gitbook.io/docs/manual/transports/edgegap-relay-transport#setup \ No newline at end of file diff --git a/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt.meta b/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt.meta new file mode 100644 index 0000000..13a8228 --- /dev/null +++ b/Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a6c3a72e7e659a7459a3ba3adb15b2e0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/EdgegapLobby/_ReadMe.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash.meta b/Assets/Mirror/Examples/HexSpatialHash.meta new file mode 100644 index 0000000..f32561a --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 508be872df2cab54d8b0390b857b12e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity b/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity new file mode 100644 index 0000000..746076d --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity @@ -0,0 +1,510 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 80 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 96 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 50 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 100, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2, y: 1, z: -1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001519} + - component: {fileID: 1282001520} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 43d8e3a03523cba438aea0b8e793b390, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 9038517388597961393, guid: f3f3b7b9663c37141921929c9cfb2d5e, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + spawnPrefab: {fileID: 5490426395924729682, guid: f389723f4f9365143bac0d85db592dbd, + type: 3} + spawnPrefabsCount: 1000 + spawnPrefabSpacing: 3 + hexSpatialHash2DInterestManagement: {fileID: 1282001522} +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b8b055f11f85ff428da471a0e625dd4, type: 3} + m_Name: + m_EditorClassIdentifier: + rebuildInterval: 1 + staticRebuildInterval: 10 + visRange: 30 + minMoveDistance: 1 + checkMethod: 1 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity.meta b/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity.meta new file mode 100644 index 0000000..da7d423 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d3ffd60e82eb25d4fb848e2becd149bf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Hex2DSpatialHash.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity b/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity new file mode 100644 index 0000000..b5667de --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity @@ -0,0 +1,509 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} +--- !u!1 &88936773 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 88936777} + - component: {fileID: 88936776} + - component: {fileID: 88936774} + - component: {fileID: 88936778} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &88936774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9021b6cc314944290986ab6feb48db79, type: 3} + m_Name: + m_EditorClassIdentifier: + height: 80 + offsetY: 40 + maxLogCount: 50 + showInEditor: 0 + hotKey: 96 +--- !u!20 &88936776 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 50 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &88936777 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 100, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!114 &88936778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 88936773} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6635375fbc6be456ea640b75add6378e, type: 3} + m_Name: + m_EditorClassIdentifier: + showGUI: 1 + showLog: 0 +--- !u!1 &535739935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 535739936} + - component: {fileID: 535739937} + m_Layer: 0 + m_Name: SpawnPosition + m_TagString: Untagged + m_Icon: {fileID: -964228994112308473, guid: 0000000000000000d000000000000000, type: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &535739936 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2, y: 0, z: 2} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &535739937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 535739935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1282001517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1282001518} + - component: {fileID: 1282001520} + - component: {fileID: 1282001519} + - component: {fileID: 1282001521} + - component: {fileID: 1282001522} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1282001518 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1282001519 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &1282001520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3291bd2e9ac86c046bb768d598cd0a3f, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 30 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 1282001521} + networkAddress: localhost + maxConnections: 1000 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 9038517388597961393, guid: 85c3b622590282745ab702bb2ae1767f, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + spawnPrefab: {fileID: 5490426395924729682, guid: f389723f4f9365143bac0d85db592dbd, + type: 3} + spawnPrefabsCount: 4096 + spawnPrefabSpacing: 8 +--- !u!114 &1282001521 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &1282001522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 58e492e77a2a1a3488412ceed5c2aa2d, type: 3} + m_Name: + m_EditorClassIdentifier: + rebuildInterval: 1 + staticRebuildInterval: 10 + visRange: 30 + cellHeight: 25 + minMoveDistance: 1 +--- !u!1 &2054208274 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2054208276} + - component: {fileID: 2054208275} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2054208275 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.8 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2054208276 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2054208274} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity.meta b/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity.meta new file mode 100644 index 0000000..7c5e88e --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e43f8c9a8ffac304d8ed2e98d0614ff8 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Hex3DSpatialHash.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Mateirals.meta b/Assets/Mirror/Examples/HexSpatialHash/Mateirals.meta new file mode 100644 index 0000000..b2aea98 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Mateirals.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49e8df070aae8144baca86f4be3c571e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat b/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat new file mode 100644 index 0000000..f0b75b5 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RandomColor + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat.meta b/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat.meta new file mode 100644 index 0000000..14da540 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 67d89500b29d14f4f909a99b79a5f2a0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Mateirals/RandomColor.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs.meta b/Assets/Mirror/Examples/HexSpatialHash/Prefabs.meta new file mode 100644 index 0000000..5f0b226 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eefa76359c38223449d0fcff0cdd2bbb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab new file mode 100644 index 0000000..0bd90e4 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab @@ -0,0 +1,170 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9038517388597961393 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1054727129312803764} + - component: {fileID: 7123971714698760007} + - component: {fileID: 2530349739548631522} + - component: {fileID: 1425317175859650176} + - component: {fileID: 3718819456640761921} + - component: {fileID: 7085035185352152729} + - component: {fileID: 3256206181403686673} + m_Layer: 0 + m_Name: Hex2DPlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1054727129312803764 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7123971714698760007 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2530349739548631522 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 67d89500b29d14f4f909a99b79a5f2a0, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &1425317175859650176 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 131039475 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &3718819456640761921 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8bd7ffa7c966c0c47be237edb68c98c8, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + offset: {x: 0, y: 40, z: -65} + rotation: {x: 35, y: 0, z: 0} + checkMethod: 0 +--- !u!114 &7085035185352152729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c71d1d9ad0bdf3d498e9caac7d172f56, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + speed: 15 + checkMethod: 0 +--- !u!114 &3256206181403686673 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8f63ea2e505fd484193fb31c5c55ca73, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0.033333335 + baselineRate: 1 + unreliableRedundancy: 0 + baselineIsDelta: 1 + debugLog: 0 + useFixedUpdate: 0 + target: {fileID: 1054727129312803764} + bufferSizeLimit: 64 + sendRate: 30 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + debugDraw: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab.meta b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab.meta new file mode 100644 index 0000000..8548180 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f3f3b7b9663c37141921929c9cfb2d5e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex2DPlayer.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab new file mode 100644 index 0000000..9932aeb --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab @@ -0,0 +1,182 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9038517388597961393 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1054727129312803764} + - component: {fileID: 7123971714698760007} + - component: {fileID: 2530349739548631522} + - component: {fileID: 1039362684665499303} + - component: {fileID: 1425317175859650176} + - component: {fileID: 1361318049349458668} + - component: {fileID: 7085035185352152729} + - component: {fileID: 3256206181403686673} + m_Layer: 0 + m_Name: Hex3DPlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1054727129312803764 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &7123971714698760007 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &2530349739548631522 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 67d89500b29d14f4f909a99b79a5f2a0, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!136 &1039362684665499303 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &1425317175859650176 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3737203753 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &1361318049349458668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71ac1e35462ffad469e77d1c2fe6c9f3, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + offset: {x: 0, y: 45, z: -85} + rotation: {x: 30, y: 0, z: 0} +--- !u!114 &7085035185352152729 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: df2e991210804be44b9ab6b7d6de4d52, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + speed: 15 +--- !u!114 &3256206181403686673 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9038517388597961393} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8f63ea2e505fd484193fb31c5c55ca73, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0.033333335 + baselineRate: 1 + unreliableRedundancy: 0 + baselineIsDelta: 1 + debugLog: 0 + target: {fileID: 1054727129312803764} + bufferSizeLimit: 64 + sendRate: 30 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + debugDraw: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab.meta b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab.meta new file mode 100644 index 0000000..6dff118 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 85c3b622590282745ab702bb2ae1767f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Prefabs/Hex3DPlayer.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab new file mode 100644 index 0000000..e642ea3 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab @@ -0,0 +1,118 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5490426395924729682 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3127827758234776022} + - component: {fileID: 8291014999714722842} + - component: {fileID: 313353148227055195} + - component: {fileID: 4504475309475852547} + - component: {fileID: 7983841345410844371} + m_Layer: 0 + m_Name: SpawnPrefab + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3127827758234776022 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5490426395924729682} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8291014999714722842 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5490426395924729682} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &313353148227055195 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5490426395924729682} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 67d89500b29d14f4f909a99b79a5f2a0, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!114 &4504475309475852547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5490426395924729682} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &7983841345410844371 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5490426395924729682} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab.meta b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab.meta new file mode 100644 index 0000000..a9f326e --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f389723f4f9365143bac0d85db592dbd +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Prefabs/SpawnPrefab.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts.meta new file mode 100644 index 0000000..6e8d603 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 481aeeeb2a2fa99469fb03fda331d565 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs new file mode 100644 index 0000000..d1eee2d --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs @@ -0,0 +1,86 @@ +using System; +using UnityEngine; + +namespace Mirror.Examples.Hex2D +{ + [AddComponentMenu("")] + [RequireComponent(typeof(HexSpatialHash2DInterestManagement))] + public class Hex2DNetworkManager : NetworkManager + { + // Overrides the base singleton so we don’t have to cast to this type everywhere. + public static new Hex2DNetworkManager singleton => (Hex2DNetworkManager)NetworkManager.singleton; + + [Header("Spawns")] + public GameObject spawnPrefab; + + [Range(1, 3000), Tooltip("Number of prefabs to spawn in a flat 2D grid across the scene.")] + public ushort spawnPrefabsCount = 1000; + + [Range(1, 10), Tooltip("Spacing between grid points in meters.")] + public byte spawnPrefabSpacing = 3; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] HexSpatialHash2DInterestManagement hexSpatialHash2DInterestManagement; + + public override void OnValidate() + { + if (Application.isPlaying) return; + base.OnValidate(); + + if (hexSpatialHash2DInterestManagement == null) + hexSpatialHash2DInterestManagement = GetComponent(); + } + + public override void OnStartClient() + { + NetworkClient.RegisterPrefab(spawnPrefab); + } + + public override void OnStartServer() + { + // Instantiate an empty GameObject to parent spawns + GameObject spawns = new GameObject("Spawns"); + Transform spawnsTransform = spawns.transform; + + int spawned = 0; + + // Spawn prefabs in a 2D grid centered around origin (0,0,0) + int gridSize = (int)Mathf.Sqrt(spawnPrefabsCount); // Square grid size based on count + + // Calculate the starting position to center the grid at (0,0,0) + float halfGrid = (gridSize - 1) * spawnPrefabSpacing * 0.5f; + float startX = -halfGrid; + float startZorY = -halfGrid; // Z for XZ, Y for XY + + //Debug.Log($"Start Positions: X={startX}, Z/Y={startZorY}, gridSize={gridSize}"); + + // Use a 2D loop for a flat grid + for (int x = 0; x < gridSize && spawned < spawnPrefabsCount; ++x) + { + for (int zOrY = 0; zOrY < gridSize && spawned < spawnPrefabsCount; ++zOrY) + { + Vector3 position = Vector3.zero; + + if (hexSpatialHash2DInterestManagement.checkMethod == HexSpatialHash2DInterestManagement.CheckMethod.XZ_FOR_3D) + { + float xPos = startX + x * spawnPrefabSpacing; + float zPos = startZorY + zOrY * spawnPrefabSpacing; + position = new Vector3(xPos, 0.5f, zPos); + } + else // XY_FOR_2D + { + float xPos = startX + x * spawnPrefabSpacing; + float yPos = startZorY + zOrY * spawnPrefabSpacing; + position = new Vector3(xPos, yPos, -0.5f); + } + + GameObject instance = Instantiate(spawnPrefab, position, Quaternion.identity, spawnsTransform); + NetworkServer.Spawn(instance); + ++spawned; + } + } + + //Debug.Log($"Spawned {spawned} objects in a {gridSize}x{gridSize} 2D grid."); + } + } +} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs.meta new file mode 100644 index 0000000..5f9a78f --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 43d8e3a03523cba438aea0b8e793b390 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs new file mode 100644 index 0000000..3add377 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs @@ -0,0 +1,49 @@ +using UnityEngine; + +namespace Mirror.Examples.Hex2D +{ + [AddComponentMenu("")] + public class Hex2DPlayer : NetworkBehaviour + { + [Range(1, 20)] + public float speed = 15f; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] HexSpatialHash2DInterestManagement.CheckMethod checkMethod; + + void Awake() + { +#if UNITY_2022_2_OR_NEWER + checkMethod = FindAnyObjectByType().checkMethod; +#else + checkMethod = FindObjectOfType().checkMethod; +#endif + } + + void Update() + { + if (!isLocalPlayer) return; + + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + Vector3 dir; + + if (checkMethod == HexSpatialHash2DInterestManagement.CheckMethod.XY_FOR_2D) + dir = new Vector3(h, v, 0); + else + dir = new Vector3(h, 0, v); + + transform.position += dir.normalized * (Time.deltaTime * speed); + } + + void OnGUI() + { + if (isLocalPlayer) + { + GUILayout.BeginArea(new Rect(10, Screen.height - 25, 300, 300)); + GUILayout.Label("Use WASD to move"); + GUILayout.EndArea(); + } + } + } +} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs.meta new file mode 100644 index 0000000..eecf642 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c71d1d9ad0bdf3d498e9caac7d172f56 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs new file mode 100644 index 0000000..9477237 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs @@ -0,0 +1,95 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +// This sets up the scene camera for the local player + +namespace Mirror.Examples.Hex2D +{ + [AddComponentMenu("")] + [DisallowMultipleComponent] + public class Hex2DPlayerCamera : NetworkBehaviour + { + Camera mainCam; + + public Vector3 offset = new Vector3(0f, 40f, -65f); + public Vector3 rotation = new Vector3(35f, 0f, 0f); + + [Header("Diagnostics")] + [ReadOnly, SerializeField] HexSpatialHash2DInterestManagement.CheckMethod checkMethod; + + void Awake() + { + mainCam = Camera.main; +#if UNITY_2022_2_OR_NEWER + checkMethod = FindAnyObjectByType().checkMethod; +#else + checkMethod = FindObjectOfType().checkMethod; +#endif + } + + public override void OnStartLocalPlayer() + { + if (mainCam != null) + { + // configure and make camera a child of player with 3rd person offset + mainCam.transform.SetParent(transform); + + if (checkMethod == HexSpatialHash2DInterestManagement.CheckMethod.XY_FOR_2D) + { + mainCam.orthographic = true; + mainCam.transform.localPosition = new Vector3(0, 0, -5f); + mainCam.transform.localEulerAngles = Vector3.zero; + } + else + { + mainCam.orthographic = false; + mainCam.transform.localPosition = offset; + mainCam.transform.localEulerAngles = rotation; + } + } + else + Debug.LogWarning("PlayerCamera: Could not find a camera in scene with 'MainCamera' tag."); + } + + void OnApplicationQuit() + { + //Debug.Log("PlayerCamera.OnApplicationQuit"); + ReleaseCamera(); + } + + public override void OnStopLocalPlayer() + { + //Debug.Log("PlayerCamera.OnStopLocalPlayer"); + ReleaseCamera(); + } + + void OnDisable() + { + //Debug.Log("PlayerCamera.OnDisable"); + ReleaseCamera(); + } + + void OnDestroy() + { + //Debug.Log("PlayerCamera.OnDestroy"); + ReleaseCamera(); + } + + void ReleaseCamera() + { + if (mainCam != null && mainCam.transform.parent == transform) + { + //Debug.Log("PlayerCamera.ReleaseCamera"); + + mainCam.transform.SetParent(null); + mainCam.orthographic = true; + mainCam.orthographicSize = 15f; + mainCam.transform.localPosition = new Vector3(0f, 70f, 0f); + mainCam.transform.localEulerAngles = new Vector3(90f, 0f, 0f); + + if (mainCam.gameObject.scene != SceneManager.GetActiveScene()) + SceneManager.MoveGameObjectToScene(mainCam.gameObject, SceneManager.GetActiveScene()); + } + } + } +} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs.meta new file mode 100644 index 0000000..2708cc2 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8bd7ffa7c966c0c47be237edb68c98c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex2DPlayerCamera.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs new file mode 100644 index 0000000..f9bd2db --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs @@ -0,0 +1,70 @@ +using System; +using UnityEngine; + +namespace Mirror.Examples.Hex3D +{ + [AddComponentMenu("")] + public class Hex3DNetworkManager : NetworkManager + { + // Overrides the base singleton so we don't have to cast to this type everywhere. + public static new Hex3DNetworkManager singleton => (Hex3DNetworkManager)NetworkManager.singleton; + + [Header("Spawns")] + public GameObject spawnPrefab; + + [Range(1, 8000)] + public ushort spawnPrefabsCount = 1000; + + [Range(1, 10)] + public byte spawnPrefabSpacing = 3; + + public override void OnValidate() + { + if (Application.isPlaying) return; + base.OnValidate(); + + // Adjust spawnPrefabsCount to have an even cube root + ushort cubeRoot = (ushort)Mathf.Pow(spawnPrefabsCount, 1f / 3f); + spawnPrefabsCount = (ushort)(Mathf.Pow(cubeRoot, 3f)); + } + + public override void OnStartClient() + { + NetworkClient.RegisterPrefab(spawnPrefab); + } + + public override void OnStartServer() + { + // instantiate an empty GameObject + GameObject Spawns = new GameObject("Spawns"); + Transform SpawnsTransform = Spawns.transform; + + int spawned = 0; + + // Spawn prefabs in a cube grid centered around origin (0,0,0) + float cubeRoot = Mathf.Pow(spawnPrefabsCount, 1f / 3f); + int gridSize = Mathf.RoundToInt(cubeRoot); + + // Calculate the starting position to center the grid + float startX = -(gridSize - 1) * spawnPrefabSpacing * 0.5f; + float startY = -(gridSize - 1) * spawnPrefabSpacing * 0.5f; + float startZ = -(gridSize - 1) * spawnPrefabSpacing * 0.5f; + + //Debug.Log($"Start Positions: X={startX}, Y={startY}, Z={startZ}, gridSize={gridSize}"); + + for (int x = 0; x < gridSize; ++x) + for (int y = 0; y < gridSize; ++y) + for (int z = 0; z < gridSize; ++z) + if (spawned < spawnPrefabsCount) + { + float x1 = startX + x * spawnPrefabSpacing; + float y1 = startY + y * spawnPrefabSpacing; + float z1 = startZ + z * spawnPrefabSpacing; + Vector3 position = new Vector3(x1, y1, z1); + + NetworkServer.Spawn(Instantiate(spawnPrefab, position, Quaternion.identity, SpawnsTransform)); + ++spawned; + } + } + } +} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs.meta new file mode 100644 index 0000000..c48952e --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 3291bd2e9ac86c046bb768d598cd0a3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DNetworkManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs new file mode 100644 index 0000000..b8c2f90 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using Mirror; + +namespace Mirror.Examples.Hex3D +{ + [AddComponentMenu("")] + public class Hex3DPlayer : NetworkBehaviour + { + [Range(1, 20)] + public float speed = 10; + + void Update() + { + if (!isLocalPlayer) return; + + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + // if left shift is held, apply v to y instead of z + if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) + { + Vector3 dir = new Vector3(h, v, 0); + transform.position += dir.normalized * (Time.deltaTime * speed); + } + else + { + Vector3 dir = new Vector3(h, 0, v); + transform.position += dir.normalized * (Time.deltaTime * speed); + } + + if (Input.GetKey(KeyCode.Q)) + transform.Rotate(Vector3.up, -90 * Time.deltaTime); + if (Input.GetKey(KeyCode.E)) + transform.Rotate(Vector3.up, 90 * Time.deltaTime); + } + + void OnGUI() + { + if (isLocalPlayer) + { + GUILayout.BeginArea(new Rect(10, Screen.height - 50, 300, 300)); + GUILayout.Label("Use WASD+QE to move and rotate\nHold Shift with W/S to move up/down"); + GUILayout.EndArea(); + } + } + } +} diff --git a/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs.meta b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs.meta new file mode 100644 index 0000000..b526645 --- /dev/null +++ b/Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: df2e991210804be44b9ab6b7d6de4d52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/HexSpatialHash/Scripts/Hex3DPlayer.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation.meta b/Assets/Mirror/Examples/LagCompensation.meta new file mode 100644 index 0000000..1a29389 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1d54ff0cbb6043d69ffefca753c48ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/LagCompensation/Capture2D.cs b/Assets/Mirror/Examples/LagCompensation/Capture2D.cs new file mode 100644 index 0000000..35e6ea5 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/Capture2D.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace Mirror.Examples.LagCompensationDemo +{ + public struct Capture2D : Capture + { + public double timestamp { get; set; } + public Vector2 position; + public Vector2 size; + + public Capture2D(double timestamp, Vector2 position, Vector2 size) + { + this.timestamp = timestamp; + this.position = position; + this.size = size; + } + + public void DrawGizmo() + { + Gizmos.DrawWireCube(position, size); + } + + public static Capture2D Interpolate(Capture2D from, Capture2D to, double t) => + new Capture2D( + 0, // interpolated snapshot is applied directly. don't need timestamps. + Vector2.LerpUnclamped(from.position, to.position, (float)t), + Vector2.LerpUnclamped(from.size, to.size, (float)t) + ); + + public override string ToString() => $"(time={timestamp} pos={position} size={size})"; + } +} diff --git a/Assets/Mirror/Examples/LagCompensation/Capture2D.cs.meta b/Assets/Mirror/Examples/LagCompensation/Capture2D.cs.meta new file mode 100644 index 0000000..03f263e --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/Capture2D.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a2ccdcd0db384bf08f4150ffb08fd09b +timeCreated: 1687921611 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/Capture2D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/ClientCube.cs b/Assets/Mirror/Examples/LagCompensation/ClientCube.cs new file mode 100644 index 0000000..44bc224 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ClientCube.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirror.Examples.LagCompensationDemo +{ + public class ClientCube : MonoBehaviour + { + [Header("Components")] + public ServerCube server; + public Renderer render; + + [Header("Toggle")] + public bool interpolate = true; + + // snapshot interpolation settings + [Header("Snapshot Interpolation")] + public SnapshotInterpolationSettings snapshotSettings = + new SnapshotInterpolationSettings(); + + // runtime settings + public double bufferTime => server.sendInterval * snapshotSettings.bufferTimeMultiplier; + + // + public SortedList snapshots = new SortedList(); + + // for smooth interpolation, we need to interpolate along server time. + // any other time (arrival on client, client local time, etc.) is not + // going to give smooth results. + internal double localTimeline; + + // catchup / slowdown adjustments are applied to timescale, + // to be adjusted in every update instead of when receiving messages. + double localTimescale = 1; + + // we use EMA to average the last second worth of snapshot time diffs. + // manually averaging the last second worth of values with a for loop + // would be the same, but a moving average is faster because we only + // ever add one value. + ExponentialMovingAverage driftEma; + ExponentialMovingAverage deliveryTimeEma; // average delivery time (standard deviation gives average jitter) + + // debugging /////////////////////////////////////////////////////////// + [Header("Debug")] + public Color hitColor = Color.blue; + public Color missedColor = Color.magenta; + public Color originalColor = Color.black; + + [Header("Simulation")] + bool lowFpsMode; + double accumulatedDeltaTime; + + void Awake() + { + // defaultColor = render.sharedMaterial.color; + + // initialize EMA with 'emaDuration' seconds worth of history. + // 1 second holds 'sendRate' worth of values. + // multiplied by emaDuration gives n-seconds. + driftEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.driftEmaDuration); + deliveryTimeEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.deliveryTimeEmaDuration); + } + + // add snapshot & initialize client interpolation time if needed + public void OnMessage(Snapshot3D snap) + { + // set local timestamp (= when it was received on our end) + // Unity 2019 doesn't have Time.timeAsDouble yet + snap.localTime = NetworkTime.localTime; + + // (optional) dynamic adjustment + if (snapshotSettings.dynamicAdjustment) + { + // set bufferTime on the fly. + // shows in inspector for easier debugging :) + snapshotSettings.bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment( + server.sendInterval, + deliveryTimeEma.StandardDeviation, + snapshotSettings.dynamicAdjustmentTolerance + ); + } + + // insert into the buffer & initialize / adjust / catchup + SnapshotInterpolation.InsertAndAdjust( + snapshots, + snapshotSettings.bufferLimit, + snap, + ref localTimeline, + ref localTimescale, + server.sendInterval, + bufferTime, + snapshotSettings.catchupSpeed, + snapshotSettings.slowdownSpeed, + ref driftEma, + snapshotSettings.catchupNegativeThreshold, + snapshotSettings.catchupPositiveThreshold, + ref deliveryTimeEma); + } + + void Update() + { + // accumulated delta allows us to simulate correct low fps + deltaTime + // if necessary in client low fps mode. + accumulatedDeltaTime += Time.unscaledDeltaTime; + + // simulate low fps mode. only update once per second. + // to simulate webgl background tabs, etc. + // after a while, disable low fps mode and see how it behaves. + if (lowFpsMode && accumulatedDeltaTime < 1) return; + + // only while we have snapshots. + // timeline starts when the first snapshot arrives. + if (snapshots.Count > 0) + { + // snapshot interpolation + if (interpolate) + { + // step + SnapshotInterpolation.Step( + snapshots, + // accumulate delta is Time.unscaledDeltaTime normally. + // and sum of past 10 delta's in low fps mode. + accumulatedDeltaTime, + ref localTimeline, + localTimescale, + out Snapshot3D fromSnapshot, + out Snapshot3D toSnapshot, + out double t); + + // interpolate & apply + Snapshot3D computed = Snapshot3D.Interpolate(fromSnapshot, toSnapshot, t); + transform.position = computed.position; + } + // apply raw + else + { + Snapshot3D snap = snapshots.Values[0]; + transform.position = snap.position; + snapshots.RemoveAt(0); + } + } + + // reset simulation helpers + accumulatedDeltaTime = 0; + } + + void OnMouseDown() + { + // send the command. + // only x coordinate matters for this simple example. + if (server.CmdClicked(transform.position)) + { + Debug.Log($"Click hit!"); + FlashColor(hitColor); + } + else + { + Debug.Log($"Click missed!"); + FlashColor(missedColor); + } + } + + // simple visual indicator for better feedback. + // changes the cube's color for a short time. + void FlashColor(Color color) => + StartCoroutine(TemporarilyChangeColorToGreen(color)); + + IEnumerator TemporarilyChangeColorToGreen(Color color) + { + Renderer r = GetComponentInChildren(); + r.material.color = color; + yield return new WaitForSeconds(0.2f); + r.material.color = originalColor; + } + + void OnGUI() + { + // display buffer size as number for easier debugging. + // catchup is displayed as color state in Update() already. + const int width = 30; // fit 3 digits + const int height = 20; + Vector2 screen = Camera.main.WorldToScreenPoint(transform.position); + string str = $"{snapshots.Count}"; + GUI.Label(new Rect(screen.x - width / 2, screen.y - height / 2, width, height), str); + + // client simulation buttons on the bottom of the screen + float areaHeight = 150; + GUILayout.BeginArea(new Rect(0, Screen.height - areaHeight, Screen.width, areaHeight)); + GUILayout.Label("Click the black cube. Lag compensation will correct the latency."); + GUILayout.BeginHorizontal(); + GUILayout.Label("Client Simulation:"); + if (GUILayout.Button((lowFpsMode ? "Disable" : "Enable") + " 1 FPS")) + { + lowFpsMode = !lowFpsMode; + } + + GUILayout.Label("|"); + + if (GUILayout.Button("Timeline 10s behind")) + { + localTimeline -= 10.0; + } + if (GUILayout.Button("Timeline 1s behind")) + { + localTimeline -= 1.0; + } + if (GUILayout.Button("Timeline 0.1s behind")) + { + localTimeline -= 0.1; + } + + GUILayout.Label("|"); + + if (GUILayout.Button("Timeline 0.1s ahead")) + { + localTimeline += 0.1; + } + if (GUILayout.Button("Timeline 1s ahead")) + { + localTimeline += 1.0; + } + if (GUILayout.Button("Timeline 10s ahead")) + { + localTimeline += 10.0; + } + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + + void OnValidate() + { + // thresholds need to be <0 and >0 + snapshotSettings.catchupNegativeThreshold = Math.Min(snapshotSettings.catchupNegativeThreshold, 0); + snapshotSettings.catchupPositiveThreshold = Math.Max(snapshotSettings.catchupPositiveThreshold, 0); + } + } +} diff --git a/Assets/Mirror/Examples/LagCompensation/ClientCube.cs.meta b/Assets/Mirror/Examples/LagCompensation/ClientCube.cs.meta new file mode 100644 index 0000000..56fd696 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ClientCube.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8caf33fba9e694fef966e0b2f88f0afc +timeCreated: 1654065994 +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/ClientCube.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat b/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat new file mode 100644 index 0000000..558d872 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ClientMaterial + m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat.meta b/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat.meta new file mode 100644 index 0000000..b481534 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: e402de56ca981421cbbd922919787c15 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/ClientMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity b/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity new file mode 100644 index 0000000..a690da8 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity @@ -0,0 +1,483 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311924, g: 0.38073963, b: 0.3587269, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &89338751 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 89338755} + - component: {fileID: 89338756} + - component: {fileID: 89338757} + m_Layer: 0 + m_Name: Client Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &89338755 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89338751} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -5, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1292704308} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &89338756 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89338751} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8caf33fba9e694fef966e0b2f88f0afc, type: 3} + m_Name: + m_EditorClassIdentifier: + server: {fileID: 474480122} + render: {fileID: 1292704310} + interpolate: 1 + snapshotSettings: + bufferTimeMultiplier: 8 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 0 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + hitColor: {r: 0, g: 0, b: 1, a: 1} + missedColor: {r: 1, g: 0, b: 1, a: 1} + originalColor: {r: 0, g: 0, b: 0, a: 1} +--- !u!65 &89338757 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89338751} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: -1, z: 0} +--- !u!1 &474480117 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 474480121} + - component: {fileID: 474480120} + - component: {fileID: 474480119} + - component: {fileID: 474480122} + - component: {fileID: 474480123} + m_Layer: 0 + m_Name: Server Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!23 &474480119 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 474480117} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 163b909ba60cc435a95bb35396edda15, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &474480120 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 474480117} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &474480121 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 474480117} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -5, y: 0.5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &474480122 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 474480117} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: eb17f7222317f4b889bb4e80f69df3f9, type: 3} + m_Name: + m_EditorClassIdentifier: + client: {fileID: 89338756} + collider: {fileID: 474480123} + distance: 10 + speed: 3 + sendRate: 30 + lagCompensationSettings: + historyLimit: 4 + captureInterval: 0.4 + historyColor: {r: 1, g: 1, b: 1, a: 1} + resultDuration: 0.5 + latency: 0.05 + jitter: 0.05 + loss: 0.05 + scramble: 0.05 +--- !u!65 &474480123 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 474480117} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &1292704307 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1292704308} + - component: {fileID: 1292704311} + - component: {fileID: 1292704310} + m_Layer: 0 + m_Name: Visual Offset + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1292704308 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1292704307} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: -1, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 89338755} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1292704310 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1292704307} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: f17cbcb3229954975ab0818845a2c17f, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1292704311 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1292704307} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1961486736 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1961486739} + - component: {fileID: 1961486738} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &1961486738 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1961486736} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.26415092, g: 0.26415092, b: 0.26415092, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 7 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1961486739 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1961486736} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -11.22} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity.meta b/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity.meta new file mode 100644 index 0000000..9cdceac --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 171fa8a3c4ead4a2886e0ecd02e810c0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/MirrorLagCompensation.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/ServerCube.cs b/Assets/Mirror/Examples/LagCompensation/ServerCube.cs new file mode 100644 index 0000000..d445332 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ServerCube.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; +using Random = UnityEngine.Random; + +namespace Mirror.Examples.LagCompensationDemo +{ + public class ServerCube : MonoBehaviour + { + [Header("Components")] + public ClientCube client; + [FormerlySerializedAs("collider")] + public BoxCollider col; + + [Header("Movement")] + public float distance = 10; + public float speed = 3; + Vector3 start; + + [Header("Snapshot Interpolation")] + [Tooltip("Send N snapshots per second. Multiples of frame rate make sense.")] + public int sendRate = 30; // in Hz. easier to work with as int for EMA. easier to display '30' than '0.333333333' + public float sendInterval => 1f / sendRate; + float lastSendTime; + + [Header("Lag Compensation")] + public LagCompensationSettings lagCompensationSettings = new LagCompensationSettings(); + double lastCaptureTime; + + // lag compensation history of + Queue> history = new Queue>(); + + public Color historyColor = Color.white; + + // store latest lag compensation result to show a visual indicator + [Header("Debug")] + public double resultDuration = 0.5; + double resultTime; + Capture2D resultBefore; + Capture2D resultAfter; + Capture2D resultInterpolated; + + [Header("Latency Simulation")] + [Tooltip("Latency in seconds")] + public float latency = 0.05f; // 50 ms + [Tooltip("Latency jitter, randomly added to latency.")] + [Range(0, 1)] public float jitter = 0.05f; + [Tooltip("Packet loss in %")] + [Range(0, 1)] public float loss = 0.1f; + [Tooltip("Scramble % of unreliable messages, just like over the real network. Mirror unreliable is unordered.")] + [Range(0, 1)] public float scramble = 0.1f; + + // random + // UnityEngine.Random.value is [0, 1] with both upper and lower bounds inclusive + // but we need the upper bound to be exclusive, so using System.Random instead. + // => NextDouble() is NEVER < 0 so loss=0 never drops! + // => NextDouble() is ALWAYS < 1 so loss=1 always drops! + System.Random random = new System.Random(); + + // hold on to snapshots for a little while before delivering + // + List<(double, Snapshot3D)> queue = new List<(double, Snapshot3D)>(); + + // latency simulation: + // always a fixed value + some jitter. + float SimulateLatency() => latency + Random.value * jitter; + + // this is the average without randomness. for lag compensation math. + // in a real game, use rtt instead. + float AverageLatency() => latency + 0.5f * jitter; + + void Start() + { + start = transform.position; + } + + void Update() + { + // move on XY plane + float x = Mathf.PingPong(Time.time * speed, distance); + transform.position = new Vector3(start.x + x, start.y, start.z); + + // broadcast snapshots every interval + if (Time.time >= lastSendTime + sendInterval) + { + Send(transform.position); + lastSendTime = Time.time; + } + + Flush(); + + // capture lag compensation snapshots every interval. + // NetworkTime.localTime because Unity 2019 doesn't have 'double' time yet. + if (NetworkTime.localTime >= lastCaptureTime + lagCompensationSettings.captureInterval) + { + lastCaptureTime = NetworkTime.localTime; + Capture(); + } + } + + void Send(Vector3 position) + { + // create snapshot + // Unity 2019 doesn't have Time.timeAsDouble yet + Snapshot3D snap = new Snapshot3D(NetworkTime.localTime, 0, position); + + // simulate packet loss + bool drop = random.NextDouble() < loss; + if (!drop) + { + // simulate scramble (Random.Next is < max, so +1) + bool doScramble = random.NextDouble() < scramble; + int last = queue.Count; + int index = doScramble ? random.Next(0, last + 1) : last; + + // simulate latency + float simulatedLatency = SimulateLatency(); + // Unity 2019 doesn't have Time.timeAsDouble yet + double deliveryTime = NetworkTime.localTime + simulatedLatency; + queue.Insert(index, (deliveryTime, snap)); + } + } + + void Flush() + { + // flush ready snapshots to client + for (int i = 0; i < queue.Count; ++i) + { + (double deliveryTime, Snapshot3D snap) = queue[i]; + + // Unity 2019 doesn't have Time.timeAsDouble yet + if (NetworkTime.localTime >= deliveryTime) + { + client.OnMessage(snap); + queue.RemoveAt(i); + --i; + } + } + } + + void Capture() + { + // capture current state + Capture2D capture = new Capture2D(NetworkTime.localTime, transform.position, col.size); + + // insert into history + LagCompensation.Insert(history, lagCompensationSettings.historyLimit, NetworkTime.localTime, capture); + } + + // client says: "I was clicked here, at this time." + // server needs to rollback to validate. + // timestamp is the client's snapshot interpolated timeline! + public bool CmdClicked(Vector2 position) + { + // never trust the client: estimate client time instead. + // https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking + // the estimation is very good. the error is as low as ~6ms for the demo. + double rtt = AverageLatency() * 2; // the function needs rtt, which is latency * 2 + double estimatedTime = LagCompensation.EstimateTime(NetworkTime.localTime, rtt, client.bufferTime); + + // compare estimated time with actual client time for debugging + double error = Math.Abs(estimatedTime - client.localTimeline); + Debug.Log($"CmdClicked: serverTime={NetworkTime.localTime:F3} clientTime={client.localTimeline:F3} estimatedTime={estimatedTime:F3} estimationError={error:F3} position={position}"); + + // sample the history to get the nearest snapshots around 'timestamp' + if (LagCompensation.Sample(history, estimatedTime, lagCompensationSettings.captureInterval, out resultBefore, out resultAfter, out double t)) + { + // interpolate to get a decent estimation at exactly 'timestamp' + resultInterpolated = Capture2D.Interpolate(resultBefore, resultAfter, t); + resultTime = NetworkTime.localTime; + + // check if there really was a cube at that time and position + Bounds bounds = new Bounds(resultInterpolated.position, resultInterpolated.size); + if (bounds.Contains(position)) + { + return true; + } + else Debug.Log($"CmdClicked: interpolated={resultInterpolated} doesn't contain {position}"); + } + else Debug.Log($"CmdClicked: history doesn't contain {estimatedTime:F3}"); + + return false; + } + + void OnDrawGizmos() + { + // should we apply special colors to an active result? + bool showResult = NetworkTime.localTime <= resultTime + resultDuration; + + // draw interpoalted result first. + // history meshcubes should write over it for better visibility. + if (showResult) + { + Gizmos.color = Color.black; + Gizmos.DrawCube(resultInterpolated.position, resultInterpolated.size); + } + + // draw history + Gizmos.color = historyColor; + LagCompensation.DrawGizmos(history); + + // draw result samples after. useful to see the selection process. + if (showResult) + { + Gizmos.color = Color.cyan; + Gizmos.DrawWireCube(resultBefore.position, resultBefore.size); + Gizmos.DrawWireCube(resultAfter.position, resultAfter.size); + } + } + } +} diff --git a/Assets/Mirror/Examples/LagCompensation/ServerCube.cs.meta b/Assets/Mirror/Examples/LagCompensation/ServerCube.cs.meta new file mode 100644 index 0000000..c9ff8b6 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ServerCube.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: eb17f7222317f4b889bb4e80f69df3f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/ServerCube.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat b/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat new file mode 100644 index 0000000..2046f0c --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat @@ -0,0 +1,80 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ServerMaterial + m_Shader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0} + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat.meta b/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat.meta new file mode 100644 index 0000000..119aa42 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: f83d36483f2c647d9a8385d3fbb9135b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/ServerMaterial.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs b/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs new file mode 100644 index 0000000..5d4b77b --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs @@ -0,0 +1,26 @@ +// a simple snapshot with timestamp & interpolation +using UnityEngine; + +namespace Mirror.Examples.LagCompensationDemo +{ + public struct Snapshot3D : Snapshot + { + public double remoteTime { get; set; } + public double localTime { get; set; } + public Vector3 position; + + public Snapshot3D(double remoteTime, double localTime, Vector3 position) + { + this.remoteTime = remoteTime; + this.localTime = localTime; + this.position = position; + } + + public static Snapshot3D Interpolate(Snapshot3D from, Snapshot3D to, double t) => + new Snapshot3D( + // interpolated snapshot is applied directly. don't need timestamps. + 0, 0, + // lerp unclamped in case we ever need to extrapolate. + Vector3.LerpUnclamped(from.position, to.position, (float)t)); + } +} diff --git a/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs.meta b/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs.meta new file mode 100644 index 0000000..60572cb --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 78563da1b871d45b3a9f763a2a469b76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/Snapshot3D.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_ b/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_ new file mode 100644 index 0000000..c1a879d --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_ @@ -0,0 +1,2 @@ +otherwise it may not look entirely smooth. +even on 120 hz. \ No newline at end of file diff --git a/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_.meta b/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_.meta new file mode 100644 index 0000000..d8497f6 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 8a02664e59ea04082ba401785fdf2a3f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/_DISABLE VSYNC_ + uploadId: 736421 diff --git a/Assets/Mirror/Examples/LagCompensation/_README.txt b/Assets/Mirror/Examples/LagCompensation/_README.txt new file mode 100644 index 0000000..9e45b45 --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/_README.txt @@ -0,0 +1,6 @@ +Rollback / Lag Compensation is a standalone, Unity / netcode independent algorithm. +This is a simple demo to test it, without Mirror. +We want this to be usable in all game engines. + +The demo intentionally introduces latency so that server / client cubes are +at different positions when clicking. \ No newline at end of file diff --git a/Assets/Mirror/Examples/LagCompensation/_README.txt.meta b/Assets/Mirror/Examples/LagCompensation/_README.txt.meta new file mode 100644 index 0000000..87a9c4d --- /dev/null +++ b/Assets/Mirror/Examples/LagCompensation/_README.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b607c436b68734cb99de2663169c5b44 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/LagCompensation/_README.txt + uploadId: 736421 diff --git a/Assets/Mirror/Examples/Mirror.Examples.asmdef b/Assets/Mirror/Examples/Mirror.Examples.asmdef new file mode 100644 index 0000000..f00c85c --- /dev/null +++ b/Assets/Mirror/Examples/Mirror.Examples.asmdef @@ -0,0 +1,19 @@ +{ + "name": "Mirror.Examples", + "rootNamespace": "", + "references": [ + "GUID:30817c1a0e6d646d99c048fc403f5979", + "GUID:72872094b21c16e48b631b2224833d49", + "GUID:627104647b9c04b4ebb8978a92ecac63", + "GUID:6055be8ebefd69e48b49212b09b47b2f" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta b/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta new file mode 100644 index 0000000..f9a2b7f --- /dev/null +++ b/Assets/Mirror/Examples/Mirror.Examples.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: fecf25954bb196642ab50657689761d6 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/Mirror.Examples.asmdef + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes.meta new file mode 100644 index 0000000..bbe9ba2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 792b2d05e371c3c47ac7c4b1fa0dbfe2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta new file mode 100644 index 0000000..7a4a337 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef54d3fc8c3b6c845bb29f2d04ea7edb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta new file mode 100644 index 0000000..a372565 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5ae92b6f97224e418115c9f16c50fd8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial new file mode 100644 index 0000000..d350850 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Icosphere + dynamicFriction: 0.4 + staticFriction: 0.5 + bounciness: 0.8 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta new file mode 100644 index 0000000..9e3ce3c --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 47163bc0301c1a146bbaa4d539a6ac36 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Icosphere.physicMaterial + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial new file mode 100644 index 0000000..bd2d613 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + dynamicFriction: 0.3 + staticFriction: 0.5 + bounciness: 0.2 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta new file mode 100644 index 0000000..355e98e --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 2debad4ac21a6644faf4fc93bd5b5869 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/Player.physicMaterial + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial new file mode 100644 index 0000000..43d6617 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: RoomBounce + dynamicFriction: 0.8 + staticFriction: 0.8 + bounciness: 0.8 + frictionCombine: 1 + bounceCombine: 2 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta new file mode 100644 index 0000000..70cf721 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 2e179c076d5d0924dbf5a2de0630bdb1 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Physics/RoomBounce.physicMaterial + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta new file mode 100644 index 0000000..0953148 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e79e44ac19c0d9244bb54a0e960210e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat new file mode 100644 index 0000000..02d6c8c --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: PlayArea + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _NORMALMAP _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 2800000, guid: 443ac4c51c1c54ef08982799fce45637, type: 3} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 8, y: 8} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 2800000, guid: c23fa1f1515f4442892cfe827ab8493e, type: 3} + m_Scale: {x: 8, y: 8} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.8867924, g: 0.84346247, b: 0.7654859, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta new file mode 100644 index 0000000..d835a23 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 42fe0bcfbb65da3429ae2c289686e024 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/PlayArea.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat new file mode 100644 index 0000000..a394fe1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Player + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta new file mode 100644 index 0000000..ceee370 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 2089070a3452e6f4d866c53e51aae8f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Player.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat new file mode 100644 index 0000000..08f5003 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Prize + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 1 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta new file mode 100644 index 0000000..7680f8b --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 2becd2014627a774e9e8f668f281f1d2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Materials/Render/Prize.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta new file mode 100644 index 0000000..fbeb501 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 758bdb1e6d29abf4e96198a11d34f313 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta new file mode 100644 index 0000000..5a41527 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea3fb2e0d8b9abc43b8b628e3e550872 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj new file mode 100644 index 0000000..c6dcf15 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj @@ -0,0 +1,119 @@ +mtllib ./IcosphereC.mtl +g Icosphere +v 1.192093E-07 0.187595 0.9822463 +v 0.5257312 0.7946554 0.3035289 +v 0.8506509 -0.1875913 0.4911242 +v -0.5257308 0.7946554 0.3035289 +v 1.192093E-07 0.7946525 -0.6070641 +v 0.8506509 0.1875908 -0.4911239 +v -0.8506508 -0.1875913 0.4911242 +v 1.192093E-07 -0.7946531 0.6070642 +v 0.5257312 -0.7946556 -0.3035287 +v 1.192093E-07 -0.1875954 -0.9822463 +v -0.8506508 0.1875908 -0.4911239 +v -0.5257308 -0.7946556 -0.3035287 + +vn 0.5773501 0.3333353 0.7453553 +vn 0 0.7453575 0.666665 +vn 0 1 -3.272848E-06 +vn 0.5773502 0.745355 -0.3333357 +vn 0.9341724 0.3333336 0.127321 +vn -0.57735 0.3333354 0.7453552 +vn 0.3568219 -0.3333308 0.8726791 +vn 0.9341724 -0.3333337 -0.127321 +vn 0.3568221 0.3333309 -0.8726789 +vn -0.5773502 0.745355 -0.3333356 +vn -0.5773502 -0.7453552 0.3333353 +vn 0 -1 2.749192E-06 +vn 0 -0.7453578 -0.6666646 +vn -0.5773502 -0.3333355 -0.7453551 +vn -0.9341723 -0.3333339 -0.1273212 +vn -0.3568219 -0.3333308 0.8726791 +vn 0.5773503 -0.7453551 0.3333354 +vn 0.5773503 -0.3333354 -0.7453551 +vn -0.356822 0.3333309 -0.8726789 +vn -0.9341723 0.3333338 0.1273211 + +vt -0.5257311 1.376382 +vt 0 1.701302 +vt 0.3249197 0.8506508 +vt 1.051462 0 +vt 0 0 +vt 0.5257311 0.8506508 +vt 0.5257311 -0.8506508 +vt 0 0 +vt 1.051462 0 +vt -0.3249197 0.8506508 +vt 0 1.701302 +vt 0.5257311 1.376382 +vt -0.5257311 0.8506508 +vt 0 1.701302 +vt 0.5257311 0.8506508 +vt -1.376382 0.8506508 +vt -1.051462 1.701302 +vt -0.5257311 1.376382 +vt -0.5257311 0.3249197 +vt -0.5257311 1.376382 +vt 0.3249197 0.8506508 +vt 0 0 +vt -0.5257311 0.8506508 +vt 0.5257311 0.8506508 +vt 0.5257311 0.3249197 +vt -0.3249197 0.8506508 +vt 0.5257311 1.376382 +vt 1.376382 0.8506508 +vt 0.5257311 1.376382 +vt 1.051462 1.701302 +vt -0.5257311 0.3249197 +vt -1.051462 0 +vt -1.376382 0.8506508 +vt 0 0 +vt -1.051462 0 +vt -0.5257311 0.8506508 +vt -0.5257311 -0.8506508 +vt -1.051462 0 +vt 0 0 +vt 1.376382 0.8506508 +vt 1.051462 0 +vt 0.5257311 0.3249197 +vt 0.5257311 0.8506508 +vt 0 0 +vt -0.5257311 0.8506508 +vt -0.5257311 1.376382 +vt -0.5257311 0.3249197 +vt -1.376382 0.8506508 +vt 0.3249197 0.8506508 +vt 0 0 +vt -0.5257311 0.3249197 +vt -0.3249197 0.8506508 +vt 0.5257311 0.3249197 +vt 0 0 +vt 0.5257311 1.376382 +vt 1.376382 0.8506508 +vt 0.5257311 0.3249197 +vt 0 1.701302 +vt 0.5257311 0.8506508 +vt -0.5257311 0.8506508 + +usemtl IcosphereMat +usemap IcosphereMat +f 3/3/1 2/2/1 1/1/1 +f 1/6/2 2/5/2 4/4/2 +f 4/9/3 2/8/3 5/7/3 +f 5/12/4 2/11/4 6/10/4 +f 6/15/5 2/14/5 3/13/5 +f 1/18/6 4/17/6 7/16/6 +f 3/21/7 1/20/7 8/19/7 +f 6/24/8 3/23/8 9/22/8 +f 5/27/9 6/26/9 10/25/9 +f 4/30/10 5/29/10 11/28/10 +f 7/33/11 12/32/11 8/31/11 +f 8/36/12 12/35/12 9/34/12 +f 9/39/13 12/38/13 10/37/13 +f 10/42/14 12/41/14 11/40/14 +f 11/45/15 12/44/15 7/43/15 +f 7/48/16 8/47/16 1/46/16 +f 8/51/17 9/50/17 3/49/17 +f 9/54/18 10/53/18 6/52/18 +f 10/57/19 11/56/19 5/55/19 +f 11/60/20 7/59/20 4/58/20 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta new file mode 100644 index 0000000..c344fcd --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj.meta @@ -0,0 +1,111 @@ +fileFormatVersion: 2 +guid: 1fe56a0e685b8434ebfeb53c69b59a5e +ModelImporter: + serializedVersion: 23 + fileIDToRecycleName: + 100000: Icosphere + 100002: //RootNode + 400000: Icosphere + 400002: //RootNode + 2100000: IcosphereMat + 2300000: Icosphere + 3300000: Icosphere + 4300000: Icosphere + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: ProBuilderDefault + second: {fileID: 2100000, guid: 883a7db7f994aab478a4380ad50eda70, type: 2} + materials: + importMaterials: 1 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + optimizeMeshForGPU: 1 + keepQuads: 0 + weldVertices: 1 + preserveHierarchy: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVPackMargin: 4 + useFileScale: 1 + previousCalculatedGlobalScale: 1 + hasPreviousCalculatedGlobalScale: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + importAnimation: 1 + copyAvatar: 0 + humanDescription: + serializedVersion: 2 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + animationType: 0 + humanoidOversampling: 1 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Icosphere.obj + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta new file mode 100644 index 0000000..1eb00d1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c07f54121eb4534e85f72041ec0f196 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat new file mode 100644 index 0000000..e01a611 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Icosphere + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0, b: 0, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta new file mode 100644 index 0000000..078d4c4 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 7e6bf26596c6f564097734c7cc319e15 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Models/Icosphere/Materials/Icosphere.mat + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta new file mode 100644 index 0000000..6d235af --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90a1d98ef5d99304095438cdf9cbdc10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab new file mode 100644 index 0000000..86d6352 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab @@ -0,0 +1,233 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5513112217680870096 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5513112217680897776} + - component: {fileID: 5513112217677473488} + - component: {fileID: 5513112217678603280} + - component: {fileID: 456454062324168415} + m_Layer: 0 + m_Name: Icosphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5513112217680897776 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5513112217680897778} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &5513112217677473488 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Mesh: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} +--- !u!23 &5513112217678603280 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &456454062324168415 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870096} + m_Material: {fileID: 13400000, guid: 47163bc0301c1a146bbaa4d539a6ac36, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 1 + m_CookingOptions: 30 + m_Mesh: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} +--- !u!1 &5513112217680870098 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5513112217680897778} + - component: {fileID: -73998256042230442} + - component: {fileID: -7012348765844800875} + - component: {fileID: 499954472053551213} + - component: {fileID: -5073764247860119520} + - component: {fileID: -2850352209440038129} + m_Layer: 0 + m_Name: Icosphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5513112217680897778 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0, y: 0, z: 0} + m_LocalScale: {x: 0.8, y: 0.8, z: 0.8} + m_Children: + - {fileID: 5513112217680897776} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!54 &-73998256042230442 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + serializedVersion: 2 + m_Mass: 0.1 + m_Drag: 0.1 + m_AngularDrag: 0 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &-7012348765844800875 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1092270140 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &499954472053551213 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &-5073764247860119520 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + target: {fileID: 5513112217680897778} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 5 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-2850352209440038129 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5513112217680870098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c709489168fec9348b7f8290ee2e8466, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + force: 12 + rigidbody3D: {fileID: -73998256042230442} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta new file mode 100644 index 0000000..6cceef4 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a104de86221e66a48832c222471d4f1e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Icosphere.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab new file mode 100644 index 0000000..574d17d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab @@ -0,0 +1,406 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1430875437483682 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4216737524944602} + - component: {fileID: 33190644788701022} + - component: {fileID: 23708975923909982} + m_Layer: 0 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4216737524944602 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 3138541494209382947} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &33190644788701022 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &23708975923909982 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &1480027675339556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4822224316094678} + - component: {fileID: 114402732107420660} + - component: {fileID: 8715117357206038899} + - component: {fileID: 143011667059871024} + - component: {fileID: 4839740653866577337} + - component: {fileID: 115187108610643062} + - component: {fileID: 1849877933717427647} + - component: {fileID: 6261579163786439309} + - component: {fileID: 485255742382306150} + - component: {fileID: 114892629901890886} + m_Layer: 0 + m_Name: PlayerReliable + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4822224316094678 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3138541494209382947} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &114402732107420660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 2230035652 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &8715117357206038899 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71ac1e35462ffad469e77d1c2fe6c9f3, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + offset: {x: 0, y: 3, z: -8} + rotation: {x: 10, y: 0, z: 0} +--- !u!143 &143011667059871024 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &4839740653866577337 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 13400000, guid: 2debad4ac21a6644faf4fc93bd5b5869, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.8 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &115187108610643062 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8be750efa9df50f47b65ae156053d149, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + playerNumber: 0 + scoreIndex: 0 + matchIndex: 0 + score: 0 + clientMatchIndex: -1 +--- !u!54 &1849877933717427647 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &6261579163786439309 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &485255742382306150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8ff3ba0becae47b8b9381191598957c8, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 4822224316094678} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 0 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 0 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + onlySyncOnChangeCorrectionMultiplier: 2 + rotationSensitivity: 0.01 + positionPrecision: 0.01 + scalePrecision: 0.01 +--- !u!114 &114892629901890886 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 497221e839119e34b897d6c497cbc8e5, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 143011667059871024} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!1 &4926068573968176962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3138541494209382947} + - component: {fileID: 1736510165009824269} + - component: {fileID: 4008900414740136170} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3138541494209382947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4216737524944602} + m_Father: {fileID: 4822224316094678} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1736510165009824269 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4008900414740136170 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2089070a3452e6f4d866c53e51aae8f2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab.meta new file mode 100644 index 0000000..bd159d8 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 1f4d376d8ca693049abd1744e4c79fad +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerReliable.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab new file mode 100644 index 0000000..92e61e9 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab @@ -0,0 +1,406 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1430875437483682 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4216737524944602} + - component: {fileID: 33190644788701022} + - component: {fileID: 23708975923909982} + m_Layer: 0 + m_Name: Visor + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4216737524944602 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0.39999998, z: 0.5} + m_LocalScale: {x: 0.5, y: 0.1, z: 0.2} + m_Children: [] + m_Father: {fileID: 3138541494209382947} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &33190644788701022 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &23708975923909982 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1430875437483682} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!1 &1480027675339556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4822224316094678} + - component: {fileID: 114402732107420660} + - component: {fileID: 8715117357206038899} + - component: {fileID: 143011667059871024} + - component: {fileID: 4839740653866577337} + - component: {fileID: 115187108610643062} + - component: {fileID: 1849877933717427647} + - component: {fileID: 6261579163786439309} + - component: {fileID: 4785170489899496097} + - component: {fileID: -3930225633775199775} + m_Layer: 0 + m_Name: PlayerUnreliable + m_TagString: Player + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4822224316094678 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.08, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 3138541494209382947} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &114402732107420660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1941964038 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &8715117357206038899 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71ac1e35462ffad469e77d1c2fe6c9f3, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + offset: {x: 0, y: 3, z: -8} + rotation: {x: 10, y: 0, z: 0} +--- !u!143 &143011667059871024 +CharacterController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 0 + serializedVersion: 2 + m_Height: 2 + m_Radius: 0.5 + m_SlopeLimit: 45 + m_StepOffset: 0.3 + m_SkinWidth: 0.02 + m_MinMoveDistance: 0 + m_Center: {x: 0, y: 0, z: 0} +--- !u!136 &4839740653866577337 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Material: {fileID: 13400000, guid: 2debad4ac21a6644faf4fc93bd5b5869, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.8 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!114 &115187108610643062 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8be750efa9df50f47b65ae156053d149, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + playerNumber: 0 + scoreIndex: 0 + matchIndex: 0 + score: 0 + clientMatchIndex: -1 +--- !u!54 &1849877933717427647 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &6261579163786439309 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &4785170489899496097 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a553cb17010b2403e8523b558bffbc14, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 1 + syncMode: 0 + syncInterval: 0 + target: {fileID: 4822224316094678} + syncPosition: 1 + syncRotation: 1 + syncScale: 0 + onlySyncOnChange: 1 + compressRotation: 1 + interpolatePosition: 1 + interpolateRotation: 1 + interpolateScale: 1 + coordinateSpace: 0 + timelineOffset: 0 + showGizmos: 0 + showOverlay: 0 + overlayColor: {r: 0, g: 0, b: 0, a: 0.5} + bufferResetMultiplier: 3 + positionSensitivity: 0.01 + rotationSensitivity: 0.01 + scaleSensitivity: 0.01 +--- !u!114 &-3930225633775199775 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1480027675339556} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f81b59082839c2e40938767457bb91ae, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + characterController: {fileID: 143011667059871024} + ControllerUIPrefab: {fileID: 644766297742565710, guid: 7beee247444994f0281dadde274cc4af, + type: 3} + moveKeys: + Forward: 119 + Back: 115 + StrafeLeft: 97 + StrafeRight: 100 + TurnLeft: 113 + TurnRight: 101 + Jump: 32 + optionsKeys: + MouseSteer: 109 + AutoRun: 114 + ToggleUI: 117 + controlOptions: 4 + maxMoveSpeed: 8 + inputSensitivity: 2 + inputGravity: 2 + maxTurnSpeed: 100 + turnAcceleration: 3 + initialJumpSpeed: 2.5 + maxJumpSpeed: 3.5 + jumpAcceleration: 4 + runtimeData: + _horizontal: 0 + _vertical: 0 + _turnSpeed: 0 + _jumpSpeed: 0 + _animVelocity: 0 + _animRotation: 0 + _mouseInputX: 0 + _mouseSensitivity: 0 + _groundState: 0 + _direction: {x: 0, y: 0, z: 0} + _velocity: {x: 0, y: 0, z: 0} + _controllerUI: {fileID: 0} +--- !u!1 &4926068573968176962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3138541494209382947} + - component: {fileID: 1736510165009824269} + - component: {fileID: 4008900414740136170} + m_Layer: 0 + m_Name: Capsule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3138541494209382947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4216737524944602} + m_Father: {fileID: 4822224316094678} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &1736510165009824269 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &4008900414740136170 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4926068573968176962} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2089070a3452e6f4d866c53e51aae8f2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab.meta new file mode 100644 index 0000000..aa6ec88 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 8f9e691c1c5e6c8459a8e05388f9329e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/PlayerUnreliable.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab new file mode 100644 index 0000000..8b091a2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab @@ -0,0 +1,198 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1139254171913846 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4362442735993418} + - component: {fileID: 135606878775227198} + - component: {fileID: 6909319328281960030} + - component: {fileID: 114251241889735402} + - component: {fileID: 5119366209337690377} + - component: {fileID: 114048121767222990} + m_Layer: 0 + m_Name: Reward + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 4294967295 + m_IsActive: 1 +--- !u!4 &4362442735993418 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: -1000, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7524893234998283593} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!135 &135606878775227198 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Material: {fileID: 0} + m_IsTrigger: 1 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.3 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &6909319328281960030 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 1 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!114 &114251241889735402 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1863100618 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &5119366209337690377 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a91a718a70d01b347b75cb768a6f1a92, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0 + color: + serializedVersion: 2 + rgba: 4278190080 +--- !u!114 &114048121767222990 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139254171913846} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 10da7fdf8caa1eb4697658bf129457fa, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + randomColor: {fileID: 5119366209337690377} + available: 1 +--- !u!1 &5133204039361288107 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7524893234998283593} + - component: {fileID: 8440477969432842110} + - component: {fileID: 6355089084613864400} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7524893234998283593 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.3, y: 0.3, z: 0.3} + m_Children: [] + m_Father: {fileID: 4362442735993418} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8440477969432842110 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6355089084613864400 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5133204039361288107} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 2becd2014627a774e9e8f668f281f1d2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab.meta new file mode 100644 index 0000000..d54d68f --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 8cec47ed46e0eff45966a5173d3aa0d3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Prefabs/Reward.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md new file mode 100644 index 0000000..29fd22a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md @@ -0,0 +1,34 @@ +# Multiple Additive Scenes Example + +In Build Settings, remove all scenes and add both of the scenes from the Scenes folder in the following order: + +- Main +- Game + +Open the Main scene in the Editor and make sure the Game Scene field in the MultiScene Network Manager on the Network scene object contains the Game scene. This is already setup by default, but if the Main scene was opened and saved before putting the scenes in the Build Settings list, the Game Scene field may be cleared accidentally. + +## MultiScene Network Manager + +The MultiScene Network Manager is derived from the base Network Manager and is responsible for additively loading the subscene instances and placing the players in their respective subscene instances and initializing player SyncVars. It has a Game Scene field where the Game subscene is assigned, and an Instances field to set how many instances are loaded on the server. + +In this example, the subscene instances are additively loaded on the server with `localPhysicsMode = LocalPhysicsMode.Physics3D`. Physics subscenes do not auto-simulate, so each scene has a game object with a generic `PhysicsSimulator` script on it. This script does nothing on the client, only on the server. + +Clients only ever have one instance of the subscene additively loaded (without `localPhysicsMode`), while server has them all. All networked objects have a `NetworkSceneChecker` component which is what isolates them to their specific subscene. + +## Playing in the Instances + +File -\> Build and Run + +Start at least 3 built instances: These will all be client players. + +Press Play in the Editor and click Host (Server + Client) in the HUD - This will be the host and the 1st player. You can also use Server Only if you prefer. + +Click Client in the built instances. + +- WASDQE keys to move & turn your player capsule, Space to jump. + +- Colliding with the small colored spheres scores points base on their color. + +- Colliding with the larger tumblers sends them rolling around...they're server-side non-kinematic rigidbodies. + +- Only scores for the players in the same subscene are shown at the top of the game window. diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta new file mode 100644 index 0000000..c8de65c --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 915d7b115a88c7c409dadf5bfc543737 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/README.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta new file mode 100644 index 0000000..d749d32 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 060de58cc46acdf4b92e21c43400aa58 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity new file mode 100644 index 0000000..24d16cb --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity @@ -0,0 +1,779 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000004, guid: a8cb0bce5a2ae204c99b493a474f134d, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &473309615 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 473309616} + m_Layer: 0 + m_Name: Tumblers + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &473309616 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 473309615} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 535961556} + - {fileID: 1069065321} + - {fileID: 2061474489} + - {fileID: 1072549450} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &535961555 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2357680917 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &535961556 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 535961555} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1069065320 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2631545699 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &1069065321 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 1069065320} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1072549449 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 634817531 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: -5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &1072549450 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 1072549449} + m_PrefabAsset: {fileID: 0} +--- !u!1 &1305256737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1305256745} + - component: {fileID: 1305256744} + - component: {fileID: 1305256742} + - component: {fileID: 1305256743} + - component: {fileID: 1305256741} + - component: {fileID: 1305256740} + - component: {fileID: 1305256739} + - component: {fileID: 1305256738} + - component: {fileID: 1305256746} + m_Layer: 0 + m_Name: PlayArea + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &1305256738 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: 5} +--- !u!65 &1305256739 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 10, y: 8, z: 0.1} + m_Center: {x: 0, y: 4, z: -5} +--- !u!65 &1305256740 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: 5, y: 4, z: 0} +--- !u!65 &1305256741 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 13400000, guid: 2e179c076d5d0924dbf5a2de0630bdb1, type: 2} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.1, y: 8, z: 10} + m_Center: {x: -5, y: 4, z: 0} +--- !u!23 &1305256742 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 4294967295 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 42fe0bcfbb65da3429ae2c289686e024, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!64 &1305256743 +MeshCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 4 + m_Convex: 0 + m_CookingOptions: 30 + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &1305256744 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1305256745 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 4, y: 1, z: 4} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1305256746 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1305256737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 3504801306 + _assetId: 0 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!1001 &2061474488 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 473309616} + m_Modifications: + - target: {fileID: -7012348765844800875, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: sceneId + value: 2066882912 + objectReference: {fileID: 0} + - target: {fileID: 456454062324168415, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217677473488, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Mesh + value: + objectReference: {fileID: 4300000, guid: 1fe56a0e685b8434ebfeb53c69b59a5e, type: 3} + - target: {fileID: 5513112217678603280, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 7e6bf26596c6f564097734c7cc319e15, type: 2} + - target: {fileID: 5513112217680870098, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_Name + value: Icosphere + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.x + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.y + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: + - {fileID: -8786580539857106334, guid: a104de86221e66a48832c222471d4f1e, type: 3} + m_SourcePrefab: {fileID: 100100000, guid: a104de86221e66a48832c222471d4f1e, type: 3} +--- !u!4 &2061474489 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 5513112217680897778, guid: a104de86221e66a48832c222471d4f1e, + type: 3} + m_PrefabInstance: {fileID: 2061474488} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &743218413121761650 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 440985591853936351, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_Name + value: PhysicsSimulator + objectReference: {fileID: 0} + - target: {fileID: 2581897434666803994, guid: 99d75386017b4ba44ad1482ee7938f5a, + type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 99d75386017b4ba44ad1482ee7938f5a, type: 3} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity.meta new file mode 100644 index 0000000..d33f31a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d45ed07e5475d4740812c97ae565255c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.meta new file mode 100644 index 0000000..044d477 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d22f54b8b4c23824b9209ce1cbfe08b3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity new file mode 100644 index 0000000..310460a --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity @@ -0,0 +1,878 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 690741348} + m_IndirectSpecularColor: {r: 0.4366757, g: 0.48427194, b: 0.5645252, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 112000000, guid: 21b3a9f85913f2a4dbfaff18018db43a, + type: 2} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &2272925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2272928} + - component: {fileID: 2272927} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &2272927 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2272925} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 25 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &2272928 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2272925} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &69965666 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 69965670} + - component: {fileID: 69965669} + - component: {fileID: 69965667} + - component: {fileID: 69965671} + - component: {fileID: 69965668} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &69965667 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &69965668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b979f26c95d34324ba005bfacfa9c4fc, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &69965669 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b982a1fd37427e64e8310a863d03d2c9, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 69965671} + networkAddress: localhost + maxConnections: 100 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 1480027675339556, guid: 1f4d376d8ca693049abd1744e4c79fad, + type: 3} + autoCreatePlayer: 1 + playerSpawnMethod: 1 + spawnPrefabs: [] + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + rewardPrefab: {fileID: 1139254171913846, guid: 8cec47ed46e0eff45966a5173d3aa0d3, + type: 3} + poolSize: 20 + instances: 2 + gameScene: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesGame.unity +--- !u!4 &69965670 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &69965671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 69965666} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!1 &204334129 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 204334130} + - component: {fileID: 204334131} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &204334130 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 204334129} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 1.02, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &204334131 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 204334129} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &263230754 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 263230755} + - component: {fileID: 263230756} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &263230755 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 263230754} + m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956} + m_LocalPosition: {x: -15, y: 1.02, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0} +--- !u!114 &263230756 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 263230754} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &290557149 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 290557150} + - component: {fileID: 290557151} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &290557150 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 290557149} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: -15, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} +--- !u!114 &290557151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 290557149} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &690741347 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 690741349} + - component: {fileID: 690741348} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &690741348 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 690741347} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 0.990566, g: 0.9496818, b: 0.82702917, a: 1} + m_Intensity: 0.5 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 0.7 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &690741349 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 690741347} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &733367779 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 733367780} + - component: {fileID: 733367781} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &733367780 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733367779} + m_LocalRotation: {x: -0, y: 1, z: -0, w: 0} + m_LocalPosition: {x: 0, y: 1.02, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!114 &733367781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 733367779} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &990635329 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 990635330} + - component: {fileID: 990635331} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &990635330 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 990635329} + m_LocalRotation: {x: 0, y: 0.92387956, z: 0, w: 0.38268343} + m_LocalPosition: {x: -15, y: 1.02, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 135, z: 0} +--- !u!114 &990635331 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 990635329} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1067574963 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1067574966} + - component: {fileID: 1067574965} + - component: {fileID: 1067574964} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1067574964 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067574963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1067574965 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067574963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1067574966 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067574963} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1445635739 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1445635740} + m_Layer: 0 + m_Name: StartPositions + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1445635740 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1445635739} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 733367780} + - {fileID: 2127619492} + - {fileID: 1975674813} + - {fileID: 1760045337} + - {fileID: 204334130} + - {fileID: 263230755} + - {fileID: 290557150} + - {fileID: 990635330} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1760045336 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1760045337} + - component: {fileID: 1760045338} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1760045337 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1760045336} + m_LocalRotation: {x: 0, y: 0.3826836, z: -0, w: -0.92387944} + m_LocalPosition: {x: 15, y: 1.02, z: -15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 315, z: 0} +--- !u!114 &1760045338 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1760045336} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1975674812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1975674813} + - component: {fileID: 1975674814} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1975674813 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975674812} + m_LocalRotation: {x: 0, y: 0.7071068, z: -0, w: -0.7071068} + m_LocalPosition: {x: 15, y: 1.02, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 270, z: 0} +--- !u!114 &1975674814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975674812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2127619491 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2127619492} + - component: {fileID: 2127619493} + m_Layer: 0 + m_Name: PlayerStart + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2127619492 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2127619491} + m_LocalRotation: {x: 0, y: 0.9238796, z: -0, w: -0.38268325} + m_LocalPosition: {x: 15, y: 1.02, z: 15} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1445635740} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 225, z: 0} +--- !u!114 &2127619493 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2127619491} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 41f84591ce72545258ea98cb7518d8b9, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity.meta new file mode 100644 index 0000000..598a31e --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0fa8b7965660de64f8aefd6b64f18a08 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset new file mode 100644 index 0000000000000000000000000000000000000000..6d4547313c1d49abd59336c071eba6034684ef41 GIT binary patch literal 18160 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset.meta new file mode 100644 index 0000000..9b9cf50 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 21b3a9f85913f2a4dbfaff18018db43a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 112000000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/LightingData.asset + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr new file mode 100644 index 0000000000000000000000000000000000000000..5bbe43347c8543094e52a13a5eb480b139a0961b GIT binary patch literal 110488 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 literal 0 HcmV?d00001 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr.meta new file mode 100644 index 0000000..e37f155 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr.meta @@ -0,0 +1,99 @@ +fileFormatVersion: 2 +guid: eb20d63193149d64b8ea05f8d742c345 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 1 + seamlessCubemap: 1 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 0 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 2 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 100 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scenes/MirrorMultipleAdditiveScenesMain/ReflectionProbe-0.exr + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta new file mode 100644 index 0000000..bcb2ac2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d930bed284ca5040b2743524031cc13 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs new file mode 100644 index 0000000..45426c5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs @@ -0,0 +1,179 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [AddComponentMenu("")] + public class MultiSceneNetManager : NetworkManager + { + [Header("Spawner Setup")] + [Tooltip("Reward Prefab for the Spawner")] + public GameObject rewardPrefab; + public byte poolSize = 20; + + [Header("MultiScene Setup")] + public int instances = 3; + + [Scene] + public string gameScene; + + // This is set true after server loads all subscene instances + bool subscenesLoaded; + + // subscenes are added to this list as they're loaded + readonly List subScenes = new List(); + + // Sequential index used in round-robin deployment of players into instances and score positioning + int clientIndex; + + #region Server System Callbacks + + /// + /// Called on the server when a client adds a new player with NetworkClient.AddPlayer. + /// The default implementation for this function creates a new player object from the playerPrefab. + /// + /// Connection from client. + public override void OnServerAddPlayer(NetworkConnectionToClient conn) + { + StartCoroutine(OnServerAddPlayerDelayed(conn)); + } + + // This delay is mostly for the host player that loads too fast for the + // server to have subscenes async loaded from OnStartServer ahead of it. + IEnumerator OnServerAddPlayerDelayed(NetworkConnectionToClient conn) + { + // wait for server to async load all subscenes for game instances + while (!subscenesLoaded) + yield return null; + + // Send Scene message to client to additively load the game scene + conn.Send(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.LoadAdditive }); + + // Wait for end of frame before adding the player to ensure Scene Message goes first + yield return new WaitForEndOfFrame(); + + Transform startPos = GetStartPosition(); + GameObject player = startPos != null + ? Instantiate(playerPrefab, startPos.position, startPos.rotation) + : Instantiate(playerPrefab); + + // instantiating a "Player" prefab gives it the name "Player(clone)" + // => appending the connectionId is WAY more useful for debugging! + player.name = $"{playerPrefab.name} [connId={conn.connectionId}]"; + + PlayerScore playerScore = player.GetComponent(); + playerScore.playerNumber = clientIndex; + playerScore.scoreIndex = clientIndex / subScenes.Count; + playerScore.matchIndex = clientIndex % subScenes.Count; + + // Do this only on server, not on clients + // This is what allows Scene Interest Management + // to isolate matches per scene instance on server. + if (subScenes.Count > 0) + SceneManager.MoveGameObjectToScene(player, subScenes[clientIndex % subScenes.Count]); + + NetworkServer.AddPlayerForConnection(conn, player); + clientIndex++; + } + + #endregion + + #region Start & Stop Callbacks + + /// + /// This is invoked when a server is started - including when a host is started. + /// StartServer has multiple signatures, but they all cause this hook to be called. + /// + public override void OnStartServer() + { + StartCoroutine(ServerLoadSubScenes()); + } + + // We're additively loading scenes, so GetSceneAt(0) will return the main "container" scene, + // therefore we start the index at one and loop through instances value inclusively. + // If instances is zero, the loop is bypassed entirely. + IEnumerator ServerLoadSubScenes() + { + for (int index = 1; index <= instances; index++) + { + yield return SceneManager.LoadSceneAsync(gameScene, new LoadSceneParameters { loadSceneMode = LoadSceneMode.Additive, localPhysicsMode = LocalPhysicsMode.Physics3D }); + + Scene newScene = SceneManager.GetSceneAt(index); + subScenes.Add(newScene); + } + + Spawner.InitializePool(rewardPrefab, poolSize); + + foreach (Scene scene in subScenes) + if (scene.IsValid()) + Spawner.InitialSpawn(scene); + + subscenesLoaded = true; + } + + /// + /// This is called when a server is stopped - including when a host is stopped. + /// + public override void OnStopServer() + { + NetworkServer.SendToAll(new SceneMessage { sceneName = gameScene, sceneOperation = SceneOperation.UnloadAdditive }); + + if (gameObject.activeSelf) + StartCoroutine(ServerUnloadSubScenes()); + + Spawner.ClearPool(); + clientIndex = 0; + } + + // Unload the subScenes and unused assets and clear the subScenes list. + IEnumerator ServerUnloadSubScenes() + { + for (int index = 0; index < subScenes.Count; index++) + if (subScenes[index].IsValid()) + yield return SceneManager.UnloadSceneAsync(subScenes[index]); + + subScenes.Clear(); + subscenesLoaded = false; + + yield return Resources.UnloadUnusedAssets(); + } + + public override void OnClientSceneChanged() + { + // Don't initialize the pool for host client because it's + // already initialized in OnRoomServerSceneChanged + if (!NetworkServer.active && SceneManager.sceneCount > 1) + Spawner.InitializePool(rewardPrefab, poolSize); + + base.OnClientSceneChanged(); + } + + // Unload all but the active scene, which is the "container" scene + IEnumerator ClientUnloadSubScenes() + { + for (int index = 0; index < SceneManager.sceneCount; index++) + if (SceneManager.GetSceneAt(index) != SceneManager.GetActiveScene()) + yield return SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(index)); + } + + /// + /// This is called when a client is stopped. + /// + public override void OnStopClient() + { + // Clear the pool when stopping client + // Only do this if we're not the host client because + // pool needs to remain active for remote clients + if (!NetworkServer.active) + Spawner.ClearPool(); + + // Make sure we're not in ServerOnly mode now after stopping host client + if (mode == NetworkManagerMode.Offline) + if (gameObject.activeSelf) StartCoroutine(ClientUnloadSubScenes()); + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta new file mode 100644 index 0000000..515d168 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: b982a1fd37427e64e8310a863d03d2c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/MultiSceneNetManager.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs new file mode 100644 index 0000000..811a301 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [RequireComponent(typeof(Rigidbody))] + public class PhysicsCollision : NetworkBehaviour + { + [Tooltip("how forcefully to push this object")] + public float force = 12; + + public Rigidbody rigidbody3D; + + protected override void OnValidate() + { + base.OnValidate(); + + if (rigidbody3D == null) + rigidbody3D = GetComponent(); + } + + void Start() + { + rigidbody3D.isKinematic = !isServer; + } + + [ServerCallback] + void OnCollisionStay(Collision other) + { + if (other.gameObject.CompareTag("Player")) + { + // get direction from which player is contacting object + Vector3 direction = other.contacts[0].normal; + + // zero the y and normalize so we don't shove this through the floor or launch this over the wall + direction.y = 0; + direction = direction.normalized; + + // push this away from player...a bit less force for host player + if (other.gameObject.GetComponent().connectionToClient.connectionId == NetworkConnection.LocalConnectionId) + rigidbody3D.AddForce(direction * force * .5f); + else + rigidbody3D.AddForce(direction * force); + } + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta new file mode 100644 index 0000000..2bae1b3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c709489168fec9348b7f8290ee2e8466 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PhysicsCollision.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs new file mode 100644 index 0000000..08238b2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + public class PlayerScore : NetworkBehaviour + { + [SyncVar] + public int playerNumber; + + [SyncVar] + public int scoreIndex; + + [SyncVar] + public int matchIndex; + + [SyncVar] + public uint score; + + public int clientMatchIndex = -1; + + void OnGUI() + { + if (!isServerOnly && !isLocalPlayer && clientMatchIndex < 0) + clientMatchIndex = NetworkClient.connection.identity.GetComponent().matchIndex; + + if (isLocalPlayer || matchIndex == clientMatchIndex) + GUI.Box(new Rect(10f + (scoreIndex * 110), 10f, 100f, 25f), $"P{playerNumber}: {score}"); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta new file mode 100644 index 0000000..2a2fa9d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8be750efa9df50f47b65ae156053d149 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/PlayerScore.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs new file mode 100644 index 0000000..9644f25 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs @@ -0,0 +1,65 @@ +using UnityEngine; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + [AddComponentMenu("")] + [RequireComponent(typeof(Common.RandomColor))] + public class Reward : NetworkBehaviour + { + [Header("Components")] + public Common.RandomColor randomColor; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] + bool available = true; + + protected override void OnValidate() + { + if (Application.isPlaying) return; + + base.OnValidate(); + Reset(); + } + + void Reset() + { + // Default position out of reach + transform.position = new Vector3(0, -1000, 0); + + if (randomColor == null) + randomColor = GetComponent(); + } + + public override void OnStartServer() + { + available = true; + } + + [ServerCallback] + void OnTriggerEnter(Collider other) + { + // Don't process collisions when it's in the pool + if (!gameObject.activeSelf) return; + + // Set up physics layers to prevent this from being called by non-players + // and eliminate the need for a tag check here. + if (!other.CompareTag("Player")) return; + + // This is a fast switch to prevent two players claiming the reward in a bang-bang close contest for it. + // First to trigger turns it off, pending the object being destroyed a few frames later. + if (!available) + return; + + available = false; + + // Calculate the points from the color...lighter scores higher as the average approaches 255 + // UnityEngine.Color RGB values are byte 0 to 255 + uint points = (uint)((randomColor.color.r + randomColor.color.g + randomColor.color.b) / 3); + + // award the points via SyncVar on Player's PlayerScore + other.GetComponent().score += points; + + Spawner.RecycleReward(gameObject); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta new file mode 100644 index 0000000..c19dbed --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 10da7fdf8caa1eb4697658bf129457fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Reward.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs new file mode 100644 index 0000000..6ce63a3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs @@ -0,0 +1,107 @@ +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Mirror.Examples.MultipleAdditiveScenes +{ + internal static class Spawner + { + static GameObject prefab; + static byte poolSize = 10; + static Pool pool; + static ushort counter; + + internal static void InitializePool(GameObject poolPrefab, byte count) + { + prefab = poolPrefab; + poolSize = count; + + NetworkClient.RegisterPrefab(prefab, SpawnHandler, UnspawnHandler); + pool = new Pool(CreateNew, poolSize); + } + + internal static void ClearPool() + { + if (prefab == null) return; + + NetworkClient.UnregisterPrefab(prefab); + + if (pool == null) return; + + // destroy all objects in pool + while (pool.Count > 0) + Object.Destroy(pool.Get()); + + counter = 0; + pool = null; + } + + static GameObject SpawnHandler(SpawnMessage msg) => Get(msg.position, msg.rotation); + + static void UnspawnHandler(GameObject spawned) => Return(spawned); + + static GameObject CreateNew() + { + // use this object as parent so that objects dont crowd hierarchy + GameObject next = Object.Instantiate(prefab); + counter++; + next.name = $"{prefab.name}_pooled_{counter:00}"; + next.SetActive(false); + return next; + } + + public static GameObject Get(Vector3 position, Quaternion rotation) + { + GameObject next = pool.Get(); + + // set position/rotation and set active + next.transform.SetPositionAndRotation(position, rotation); + next.SetActive(true); + return next; + } + + // Used to put object back into pool so they can b + // Should be used on server after unspawning an object + // Used on client by NetworkClient to unspawn objects + public static void Return(GameObject spawned) + { + // disable object + spawned.SetActive(false); + + // move the object out of reach so OnTriggerEnter doesn't get called + spawned.transform.position = new Vector3(0, -1000, 0); + + // add back to pool + pool.Return(spawned); + } + + [ServerCallback] + internal static void InitialSpawn(Scene scene) + { + for (int i = 0; i < 10; i++) + SpawnReward(scene); + } + + [ServerCallback] + internal static void SpawnReward(Scene scene) + { + Vector3 spawnPosition = new Vector3(Random.Range(-19, 20), 1, Random.Range(-19, 20)); + GameObject reward = Get(spawnPosition, Quaternion.identity); + SceneManager.MoveGameObjectToScene(reward, scene); + NetworkServer.Spawn(reward); + } + + [ServerCallback] + internal static async void RecycleReward(GameObject reward) + { + NetworkServer.UnSpawn(reward); + await DelayedSpawn(reward.scene); + } + + static async Task DelayedSpawn(Scene scene) + { + await Task.Delay(new System.TimeSpan(0, 0, 1)); + SpawnReward(scene); + } + } +} diff --git a/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta new file mode 100644 index 0000000..c06b7fa --- /dev/null +++ b/Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f522bf510b49da44caa9f3ca0ac17f3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleAdditiveScenes/Scripts/Spawner.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches.meta b/Assets/Mirror/Examples/MultipleMatches.meta new file mode 100644 index 0000000..c8788e5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e1be7be6da8e2448ba40eba0daa44b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta new file mode 100644 index 0000000..7d19e91 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad2253a5702ed854995bf034be09a1ae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab new file mode 100644 index 0000000..9bf508d --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab @@ -0,0 +1,149 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4903779300334215825 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8667093524748208693} + - component: {fileID: 792638734159983555} + - component: {fileID: 2985632515421915780} + - component: {fileID: 9218727033388977555} + - component: {fileID: 2439948753870522382} + m_Layer: 5 + m_Name: CellGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8667093524748208693 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &792638734159983555 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_CullTransparentMesh: 0 +--- !u!114 &2985632515421915780 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &9218727033388977555 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2985632515421915780} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2439948753870522382} + m_MethodName: MakePlay + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &2439948753870522382 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4903779300334215825} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9cda2a394a443474689a3c6d6044f7b0, type: 3} + m_Name: + m_EditorClassIdentifier: + matchController: {fileID: 0} + cellValue: 0 + image: {fileID: 2985632515421915780} + button: {fileID: 9218727033388977555} + playerIdentity: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta new file mode 100644 index 0000000..b590bc3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5ab8c221183f0094eb04b7f6eb569e7b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Prefabs/CellGUI.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab new file mode 100644 index 0000000..33461a2 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab @@ -0,0 +1,2172 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2555295541931690112 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9152319602512786093} + - component: {fileID: 5340387473365754403} + - component: {fileID: 6419338461327946957} + m_Layer: 5 + m_Name: Grid + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9152319602512786093 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 7845801290156398150} + - {fileID: 6007826401523109089} + - {fileID: 2045714052640889548} + - {fileID: 5012654960586055004} + - {fileID: 5768719360570285027} + - {fileID: 3581888124560234741} + - {fileID: 1213482271452262600} + - {fileID: 8092575970934441626} + - {fileID: 134186364329385301} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -230} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5340387473365754403 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_CullTransparentMesh: 0 +--- !u!114 &6419338461327946957 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2555295541931690112} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 4 + m_StartCorner: 0 + m_StartAxis: 0 + m_CellSize: {x: 50, y: 50} + m_Spacing: {x: 10, y: 10} + m_Constraint: 1 + m_ConstraintCount: 3 +--- !u!1 &2923784255186993310 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2234053401096987375} + - component: {fileID: 7453676321493443231} + - component: {fileID: 4598621321729434398} + - component: {fileID: 4694292283357099176} + - component: {fileID: 1964986598517419573} + - component: {fileID: 400263754679705305} + - component: {fileID: 4082668978785527835} + - component: {fileID: 6069480080749678769} + m_Layer: 5 + m_Name: MatchController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2234053401096987375 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 6235856198463648228} + - {fileID: 9152319602512786093} + - {fileID: 8089560656303244059} + - {fileID: 5427396184031506795} + - {fileID: 3332139760985286172} + - {fileID: 6549136291348945526} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &7453676321493443231 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!114 &4598621321729434398 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!225 &4694292283357099176 +CanvasGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_Alpha: 0 + m_Interactable: 0 + m_BlocksRaycasts: 0 + m_IgnoreParentGroups: 0 +--- !u!114 &1964986598517419573 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &400263754679705305 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 1148011193 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &4082668978785527835 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5d17e718851449a6879986e45c458fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + MatchID: +--- !u!114 &6069480080749678769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2923784255186993310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9ccb1dd1fc7cc624e9bff1d0d7a5c741, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + canvasGroup: {fileID: 4694292283357099176} + gameText: {fileID: 3623013869500637742} + exitButton: {fileID: 3578082239447023245} + playAgainButton: {fileID: 505721148531914274} + winCountLocal: {fileID: 1799015512609000790} + winCountOpponent: {fileID: 5140715663012776105} + canvasController: {fileID: 0} + player1: {fileID: 0} + player2: {fileID: 0} + startingPlayer: {fileID: 0} + currentPlayer: {fileID: 0} +--- !u!1 &3002539098384373397 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5427396184031506795} + - component: {fileID: 1482480893644091453} + - component: {fileID: 5971814406204202327} + - component: {fileID: 3578082239447023245} + m_Layer: 5 + m_Name: BackButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5427396184031506795 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6237100814274483571} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 80, y: -360} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1482480893644091453 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_CullTransparentMesh: 0 +--- !u!114 &5971814406204202327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &3578082239447023245 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3002539098384373397} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 5971814406204202327} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 6069480080749678769} + m_MethodName: RequestExitGame + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &3827598301957981835 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8089560656303244059} + - component: {fileID: 4347360514208405509} + - component: {fileID: 3285613769939000379} + - component: {fileID: 505721148531914274} + m_Layer: 5 + m_Name: ReplayButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8089560656303244059 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5868794740851378326} + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -80, y: -360} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4347360514208405509 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_CullTransparentMesh: 0 +--- !u!114 &3285613769939000379 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &505721148531914274 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3827598301957981835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 3285613769939000379} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 6069480080749678769} + m_MethodName: RequestPlayAgain + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!1 &4626758344199994040 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6549136291348945526} + - component: {fileID: 8917506311834154436} + - component: {fileID: 5140715663012776105} + - component: {fileID: 676122213734729856} + m_Layer: 5 + m_Name: OpponentWinCount + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6549136291348945526 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 200, y: -220} + m_SizeDelta: {x: 150, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8917506311834154436 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_CullTransparentMesh: 0 +--- !u!114 &5140715663012776105 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &676122213734729856 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4626758344199994040} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &4990186583940393891 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6235856198463648228} + - component: {fileID: 3131614140979920454} + - component: {fileID: 3623013869500637742} + - component: {fileID: 24521910774297013} + m_Layer: 5 + m_Name: GameText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6235856198463648228 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -100} + m_SizeDelta: {x: 200, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3131614140979920454 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_CullTransparentMesh: 0 +--- !u!114 &3623013869500637742 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &24521910774297013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4990186583940393891} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &6520692455078726128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3332139760985286172} + - component: {fileID: 6960075187593147498} + - component: {fileID: 1799015512609000790} + - component: {fileID: 4004526050613360083} + m_Layer: 5 + m_Name: LocalWinCount + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3332139760985286172 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2234053401096987375} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: -200, y: -220} + m_SizeDelta: {x: 150, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6960075187593147498 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_CullTransparentMesh: 0 +--- !u!114 &1799015512609000790 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!114 &4004526050613360083 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6520692455078726128} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 1, g: 1, b: 1, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &7074721236105841979 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5868794740851378326} + - component: {fileID: 7905154098717810396} + - component: {fileID: 7932145844108874787} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5868794740851378326 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8089560656303244059} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7905154098717810396 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_CullTransparentMesh: 0 +--- !u!114 &7932145844108874787 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7074721236105841979} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Play Again +--- !u!1 &8221244113287092374 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6237100814274483571} + - component: {fileID: 5779956055286566608} + - component: {fileID: 630561348298258014} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6237100814274483571 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5427396184031506795} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5779956055286566608 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_CullTransparentMesh: 0 +--- !u!114 &630561348298258014 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8221244113287092374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Back to Lobby +--- !u!1001 &579039501550898351 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 128 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &8092575970934441626 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 579039501550898351} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &1487965888931322995 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &7845801290156398150 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 1487965888931322995} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2902895493631791574 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 16 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &5768719360570285027 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 2902895493631791574} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &3109636500741621460 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: B1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &6007826401523109089 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 3109636500741621460} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &4456088094002665321 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &5012654960586055004 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 4456088094002665321} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &5328567489950307008 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 32 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &3581888124560234741 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 5328567489950307008} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7216004328368886009 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &2045714052640889548 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 7216004328368886009} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7534684980187888381 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 64 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: A3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 6 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &1213482271452262600 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 7534684980187888381} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &8762608952144385888 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 9152319602512786093} + m_Modifications: + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: cellValue + value: 256 + objectReference: {fileID: 0} + - target: {fileID: 2439948753870522382, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: matchController + value: + objectReference: {fileID: 6069480080749678769} + - target: {fileID: 4903779300334215825, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Name + value: C3 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_RootOrder + value: 8 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 5ab8c221183f0094eb04b7f6eb569e7b, type: 3} +--- !u!224 &134186364329385301 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 8667093524748208693, guid: 5ab8c221183f0094eb04b7f6eb569e7b, + type: 3} + m_PrefabInstance: {fileID: 8762608952144385888} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta new file mode 100644 index 0000000..1f93db8 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e101d385946c91b4c81f318efc723a88 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchController.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab new file mode 100644 index 0000000..21bccf3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab @@ -0,0 +1,311 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &732536732566260629 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6013388882030083517} + - component: {fileID: 2895310434674857523} + - component: {fileID: 7191823870515597218} + m_Layer: 5 + m_Name: Players + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6013388882030083517 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3533216216399874122} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -10, y: 0} + m_SizeDelta: {x: 60, y: 30} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &2895310434674857523 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_CullTransparentMesh: 0 +--- !u!114 &7191823870515597218 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 732536732566260629} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.78431374} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: X / X +--- !u!1 &3533216216399874123 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3533216216399874122} + - component: {fileID: 3533216216399874119} + - component: {fileID: 8159776287394259959} + - component: {fileID: 8871144159682159596} + - component: {fileID: 114572912279416540} + m_Layer: 5 + m_Name: MatchGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3533216216399874122 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 8536989563668766087} + - {fileID: 6013388882030083517} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3533216216399874119 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_CullTransparentMesh: 0 +--- !u!114 &8159776287394259959 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &8871144159682159596 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8159776287394259959} + toggleTransition: 1 + graphic: {fileID: 0} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 114572912279416540} + m_MethodName: OnToggleClicked + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 + m_IsOn: 0 +--- !u!114 &114572912279416540 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3533216216399874123} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e875a237ce12c3145b20f17222f10b68, type: 3} + m_Name: + m_EditorClassIdentifier: + image: {fileID: 8159776287394259959} + toggleButton: {fileID: 8871144159682159596} + matchName: {fileID: 4525608779212400833} + playerCount: {fileID: 7191823870515597218} + canvasController: {fileID: 0} +--- !u!1 &5341423849544309394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8536989563668766087} + - component: {fileID: 3979716480785526962} + - component: {fileID: 4525608779212400833} + m_Layer: 5 + m_Name: Name + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8536989563668766087 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 3533216216399874122} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 10, y: 0} + m_SizeDelta: {x: 200, y: 30} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &3979716480785526962 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_CullTransparentMesh: 0 +--- !u!114 &4525608779212400833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5341423849544309394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.78431374} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Match X diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta new file mode 100644 index 0000000..1e0b3e5 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: df3727c2222378b4ca786485a8b09981 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchGUI.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab new file mode 100644 index 0000000..0d8ba81 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3559083313143303799 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1204658229548937417} + - component: {fileID: 7660209086417859164} + - component: {fileID: -3992624706284245286} + m_Layer: 0 + m_Name: MatchPlayer + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1204658229548937417 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7660209086417859164 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9b91ecbcc199f4492b9a91e820070131, type: 3} + m_Name: + m_EditorClassIdentifier: + sceneId: 0 + _assetId: 3049278420 + serverOnly: 0 + visibility: 0 + hasSpawned: 0 +--- !u!114 &-3992624706284245286 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3559083313143303799} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5d17e718851449a6879986e45c458fb7, type: 3} + m_Name: + m_EditorClassIdentifier: + syncDirection: 0 + syncMode: 0 + syncInterval: 0.1 + MatchID: diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta new file mode 100644 index 0000000..933a558 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 11d2414f1e120a14c98cba6866e5348f +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Prefabs/MatchPlayer.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab new file mode 100644 index 0000000..1033892 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab @@ -0,0 +1,185 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2742256683483721700 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4805460816392144898} + - component: {fileID: 4240234839557606510} + - component: {fileID: 733636089880751452} + - component: {fileID: 8081368318735942264} + m_Layer: 5 + m_Name: PlayerGUI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4805460816392144898 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4975002542353798605} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4240234839557606510 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_CullTransparentMesh: 0 +--- !u!114 &733636089880751452 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &8081368318735942264 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2742256683483721700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f61e9bc3715eb904b91222a5526f63d8, type: 3} + m_Name: + m_EditorClassIdentifier: + playerName: {fileID: 893070459539714110} +--- !u!1 &4667088617155248724 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4975002542353798605} + - component: {fileID: 8874787277914191185} + - component: {fileID: 893070459539714110} + - component: {fileID: 1559385578385937998} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4975002542353798605 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4805460816392144898} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8874787277914191185 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_CullTransparentMesh: 0 +--- !u!114 &893070459539714110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 25 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Player X +--- !u!114 &1559385578385937998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4667088617155248724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 diff --git a/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta new file mode 100644 index 0000000..ecaccf4 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 504f86497324bc040be44f6f88b6cc73 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Prefabs/PlayerGUI.prefab + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/README.md b/Assets/Mirror/Examples/MultipleMatches/README.md new file mode 100644 index 0000000..a6da1e3 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/README.md @@ -0,0 +1,9 @@ +# MultipleMatches Example + +This example demonstrates how to run a large number of non-physics games concurrently in a single game server instance. + +This would be most appropriate for Card, Board, Puzzle, and Arcade games where there is no physics involved, just presentation and messaging. + +While this example is turn-based, real-time games work just as well. + +When a match is started, a MatchController and Player objects are spawned, all with a Network Match Checker component with the same matchId set. Only clients with the same matchID get messages about each others actions and about their own match. They don't receive any data about other matches that may be running concurrently. diff --git a/Assets/Mirror/Examples/MultipleMatches/README.md.meta b/Assets/Mirror/Examples/MultipleMatches/README.md.meta new file mode 100644 index 0000000..b431e68 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/README.md.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9749e23e4e90e0646afc81061710a927 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/README.md + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes.meta b/Assets/Mirror/Examples/MultipleMatches/Scenes.meta new file mode 100644 index 0000000..af27542 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a92fd9255da5fe9449e612566195a3aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity b/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity new file mode 100644 index 0000000..fe6e4cb --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity @@ -0,0 +1,2995 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &8446050 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8446051} + - component: {fileID: 8446054} + - component: {fileID: 8446053} + - component: {fileID: 8446052} + m_Layer: 5 + m_Name: JoinButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &8446051 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 73998978} + m_Father: {fileID: 490177806} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 80, y: -160} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &8446052 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8446053} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestJoinMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &8446053 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &8446054 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8446050} + m_CullTransparentMesh: 0 +--- !u!1 &18198962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 18198963} + - component: {fileID: 18198965} + - component: {fileID: 18198964} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &18198963 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1613178153} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &18198964 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Start +--- !u!222 &18198965 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 18198962} + m_CullTransparentMesh: 0 +--- !u!1 &73998977 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 73998978} + - component: {fileID: 73998980} + - component: {fileID: 73998979} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &73998978 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 8446051} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &73998979 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Join +--- !u!222 &73998980 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 73998977} + m_CullTransparentMesh: 0 +--- !u!1 &239920241 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 239920242} + - component: {fileID: 239920244} + - component: {fileID: 239920243} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &239920242 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 716626176} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 19.999998} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &239920243 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &239920244 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 239920241} + m_CullTransparentMesh: 0 +--- !u!1 &346368339 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 346368340} + - component: {fileID: 346368342} + - component: {fileID: 346368341} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &346368340 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1108207370} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &346368341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Cancel +--- !u!222 &346368342 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 346368339} + m_CullTransparentMesh: 0 +--- !u!1 &490177805 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 490177806} + m_Layer: 5 + m_Name: LobbyView + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &490177806 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 490177805} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1005098734} + - {fileID: 1100846361} + - {fileID: 8446051} + m_Father: {fileID: 2050110697} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -200} + m_SizeDelta: {x: 1, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &492832111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 492832112} + - component: {fileID: 492832114} + - component: {fileID: 492832113} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &492832112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1205047099} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 19.999998} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &492832113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &492832114 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 492832111} + m_CullTransparentMesh: 0 +--- !u!1 &647085297 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 647085298} + - component: {fileID: 647085300} + - component: {fileID: 647085299} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &647085298 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2105646339} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &647085299 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Leave +--- !u!222 &647085300 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 647085297} + m_CullTransparentMesh: 0 +--- !u!1 &716626175 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 716626176} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &716626176 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 716626175} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 239920242} + m_Father: {fileID: 816951368} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &777606420 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 777606421} + - component: {fileID: 777606424} + - component: {fileID: 777606423} + - component: {fileID: 777606422} + m_Layer: 5 + m_Name: TitleText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &777606421 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2050110697} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -40} + m_SizeDelta: {x: 360, y: 45} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &777606422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!114 &777606423 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 0, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 35 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Tic-Tac-Toe +--- !u!222 &777606424 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 777606420} + m_CullTransparentMesh: 0 +--- !u!1 &814991252 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 814991255} + - component: {fileID: 814991254} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!20 &814991254 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814991252} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.21698111, g: 0.21698111, b: 0.21698111, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &814991255 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814991252} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &816951367 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 816951368} + - component: {fileID: 816951371} + - component: {fileID: 816951370} + - component: {fileID: 816951369} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &816951368 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 716626176} + m_Father: {fileID: 1005098734} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 20} + m_Pivot: {x: 1, y: 1} +--- !u!114 &816951369 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 239920243} + m_HandleRect: {fileID: 239920242} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &816951370 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &816951371 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 816951367} + m_CullTransparentMesh: 0 +--- !u!1 &874070006 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 874070010} + - component: {fileID: 874070009} + - component: {fileID: 874070008} + - component: {fileID: 874070007} + - component: {fileID: 874070011} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &874070007 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6442dc8070ceb41f094e44de0bf87274, type: 3} + m_Name: + m_EditorClassIdentifier: + offsetX: 0 + offsetY: 0 +--- !u!114 &874070008 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b0fecffa3f624585964b0d0eb21b18e, type: 3} + m_Name: + m_EditorClassIdentifier: + port: 7777 + DualMode: 1 + NoDelay: 1 + Interval: 10 + Timeout: 10000 + RecvBufferSize: 7361536 + SendBufferSize: 7361536 + FastResend: 2 + ReceiveWindowSize: 4096 + SendWindowSize: 4096 + MaxRetransmit: 40 + MaximizeSocketBuffers: 1 + ReliableMaxMessageSize: 297433 + UnreliableMaxMessageSize: 1194 + debugLog: 0 + statisticsGUI: 0 + statisticsLog: 0 +--- !u!114 &874070009 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b15c78bb8ab8da42a94aa0bc3081814, type: 3} + m_Name: + m_EditorClassIdentifier: + dontDestroyOnLoad: 0 + runInBackground: 1 + headlessStartMode: 1 + editorAutoStart: 0 + sendRate: 60 + autoStartServerBuild: 0 + autoConnectClientBuild: 0 + offlineScene: + onlineScene: + offlineSceneLoadDelay: 0 + transport: {fileID: 874070008} + networkAddress: localhost + maxConnections: 200 + disconnectInactiveConnections: 0 + disconnectInactiveTimeout: 60 + authenticator: {fileID: 0} + playerPrefab: {fileID: 3559083313143303799, guid: 11d2414f1e120a14c98cba6866e5348f, + type: 3} + autoCreatePlayer: 0 + playerSpawnMethod: 1 + spawnPrefabs: + - {fileID: 2923784255186993310, guid: e101d385946c91b4c81f318efc723a88, type: 3} + exceptionsDisconnect: 1 + snapshotSettings: + bufferTimeMultiplier: 2 + bufferLimit: 32 + catchupNegativeThreshold: -1 + catchupPositiveThreshold: 1 + catchupSpeed: 0.019999999552965164 + slowdownSpeed: 0.03999999910593033 + driftEmaDuration: 1 + dynamicAdjustment: 1 + dynamicAdjustmentTolerance: 1 + deliveryTimeEmaDuration: 2 + evaluationMethod: 0 + evaluationInterval: 3 + timeInterpolationGui: 0 + canvas: {fileID: 2050110693} + canvasController: {fileID: 2050110698} +--- !u!4 &874070010 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &874070011 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 874070006} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d09f5c8bf2f4747b7a9284ef5d9ce2a7, type: 3} + m_Name: + m_EditorClassIdentifier: + matchCount: 0 +--- !u!1 &1005098733 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1005098734} + - component: {fileID: 1005098737} + - component: {fileID: 1005098736} + - component: {fileID: 1005098735} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1005098734 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1348255964} + - {fileID: 816951368} + m_Father: {fileID: 490177806} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 250} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1005098735 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.19607843} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1005098736 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_CullTransparentMesh: 0 +--- !u!114 &1005098737 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1005098733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1386671669} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 25 + m_Viewport: {fileID: 1348255964} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 816951369} + m_HorizontalScrollbarVisibility: 0 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: 0 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1100846360 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1100846361} + - component: {fileID: 1100846364} + - component: {fileID: 1100846362} + - component: {fileID: 1100846363} + m_Layer: 5 + m_Name: CreateButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1100846361 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1582884915} + m_Father: {fileID: 490177806} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -80, y: -160} + m_SizeDelta: {x: 140, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1100846362 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &1100846363 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1100846362} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestCreateMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!222 &1100846364 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1100846360} + m_CullTransparentMesh: 0 +--- !u!1 &1108207369 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1108207370} + - component: {fileID: 1108207373} + - component: {fileID: 1108207372} + - component: {fileID: 1108207371} + m_Layer: 5 + m_Name: CancelButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1108207370 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 346368340} + m_Father: {fileID: 1258848447} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1108207371 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1108207372} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestCancelMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1108207372 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1108207373 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1108207369} + m_CullTransparentMesh: 0 +--- !u!1 &1132002899 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1132002900} + - component: {fileID: 1132002903} + - component: {fileID: 1132002902} + - component: {fileID: 1132002901} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1132002900 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1205047099} + m_Father: {fileID: 1538073291} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 25} + m_SizeDelta: {x: 0, y: 70} + m_Pivot: {x: 1, y: 1} +--- !u!114 &1132002901 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 492832113} + m_HandleRect: {fileID: 492832112} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1132002902 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1132002903 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1132002899} + m_CullTransparentMesh: 0 +--- !u!1 &1205047098 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1205047099} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1205047099 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1205047098} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 492832112} + m_Father: {fileID: 1132002900} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1258848446 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1258848447} + - component: {fileID: 1258848448} + m_Layer: 5 + m_Name: RoomView + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1258848447 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1258848446} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1538073291} + - {fileID: 2105646339} + - {fileID: 1108207370} + - {fileID: 1986814489} + - {fileID: 1613178153} + m_Father: {fileID: 2050110697} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 1} + m_AnchorMax: {x: 0.5, y: 1} + m_AnchoredPosition: {x: 0, y: -200} + m_SizeDelta: {x: 1, y: 1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1258848448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1258848446} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fc0f113afba9a074b9a3e4fb56f16abb, type: 3} + m_Name: + m_EditorClassIdentifier: + playerList: {fileID: 1295888617} + playerPrefab: {fileID: 2742256683483721700, guid: 504f86497324bc040be44f6f88b6cc73, + type: 3} + cancelButton: {fileID: 1108207369} + leaveButton: {fileID: 2105646338} + startButton: {fileID: 1613178154} + owner: 0 +--- !u!1 &1295888617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1295888618} + - component: {fileID: 1295888620} + - component: {fileID: 1295888619} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1295888618 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1623056866} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: -183} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1295888619 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1295888620 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1295888617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!1 &1348255963 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1348255964} + - component: {fileID: 1348255967} + - component: {fileID: 1348255966} + - component: {fileID: 1348255965} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1348255964 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1386671669} + m_Father: {fileID: 1005098734} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1348255965 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1348255966 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_CullTransparentMesh: 0 +--- !u!114 &1348255967 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1348255963} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &1386671668 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1386671669} + - component: {fileID: 1386671671} + - component: {fileID: 1386671670} + - component: {fileID: 1386671672} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1386671669 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1348255964} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: -250} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1386671670 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1386671671 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 +--- !u!114 &1386671672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1386671668} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2fafe2cfe61f6974895a912c3755e8f1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_AllowSwitchOff: 1 +--- !u!1 &1538073290 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1538073291} + - component: {fileID: 1538073294} + - component: {fileID: 1538073293} + - component: {fileID: 1538073292} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1538073291 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1623056866} + - {fileID: 1132002900} + m_Father: {fileID: 1258848447} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1538073292 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.19607843} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1538073293 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_CullTransparentMesh: 0 +--- !u!114 &1538073294 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538073290} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1295888618} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 25 + m_Viewport: {fileID: 1623056866} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 1132002901} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 2 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1582884914 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1582884915} + - component: {fileID: 1582884917} + - component: {fileID: 1582884916} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1582884915 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1100846361} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1582884916 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Create +--- !u!222 &1582884917 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1582884914} + m_CullTransparentMesh: 0 +--- !u!1 &1613178152 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1613178153} + - component: {fileID: 1613178156} + - component: {fileID: 1613178155} + - component: {fileID: 1613178154} + m_Layer: 5 + m_Name: StartButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1613178153 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 18198963} + m_Father: {fileID: 1258848447} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1613178154 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1613178155} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestStartMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1613178155 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1613178156 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1613178152} + m_CullTransparentMesh: 0 +--- !u!1 &1623056865 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1623056866} + - component: {fileID: 1623056869} + - component: {fileID: 1623056868} + - component: {fileID: 1623056867} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1623056866 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1295888618} + m_Father: {fileID: 1538073291} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: -17} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1623056867 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1623056868 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_CullTransparentMesh: 0 +--- !u!114 &1623056869 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1623056865} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &1902615731 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1902615734} + - component: {fileID: 1902615733} + - component: {fileID: 1902615732} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1902615732 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1902615733 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1902615734 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1902615731} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1986814488 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1986814489} + - component: {fileID: 1986814492} + - component: {fileID: 1986814491} + - component: {fileID: 1986814490} + m_Layer: 5 + m_Name: ReadyButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1986814489 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2133592452} + m_Father: {fileID: 1258848447} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1986814490 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1986814491} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestReadyChange + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1986814491 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1986814492 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1986814488} + m_CullTransparentMesh: 0 +--- !u!1 &2050110693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2050110697} + - component: {fileID: 2050110696} + - component: {fileID: 2050110695} + - component: {fileID: 2050110694} + - component: {fileID: 2050110698} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &2050110694 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2050110695 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &2050110696 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2050110697 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 777606421} + - {fileID: 490177806} + - {fileID: 1258848447} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &2050110698 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2050110693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c12d7cb6cdb799041927819f22a2c931, type: 3} + m_Name: + m_EditorClassIdentifier: + matchList: {fileID: 1386671668} + matchPrefab: {fileID: 3533216216399874123, guid: df3727c2222378b4ca786485a8b09981, + type: 3} + matchControllerPrefab: {fileID: 2923784255186993310, guid: e101d385946c91b4c81f318efc723a88, + type: 3} + createButton: {fileID: 1100846363} + joinButton: {fileID: 8446052} + lobbyView: {fileID: 490177805} + roomView: {fileID: 1258848446} + roomGUI: {fileID: 1258848448} + toggleGroup: {fileID: 1386671672} +--- !u!1 &2105646338 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2105646339} + - component: {fileID: 2105646342} + - component: {fileID: 2105646341} + - component: {fileID: 2105646340} + m_Layer: 5 + m_Name: LeaveButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2105646339 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 647085298} + m_Father: {fileID: 1258848447} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -120, y: -160} + m_SizeDelta: {x: 100, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2105646340 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2105646341} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 2050110698} + m_MethodName: RequestLeaveMatch + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &2105646341 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2105646342 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2105646338} + m_CullTransparentMesh: 0 +--- !u!1 &2133592451 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2133592452} + - component: {fileID: 2133592454} + - component: {fileID: 2133592453} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2133592452 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1986814489} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2133592453 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Ready +--- !u!222 &2133592454 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2133592451} + m_CullTransparentMesh: 0 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity.meta b/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity.meta new file mode 100644 index 0000000..f3e7e13 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: aa1f875396fa7d348a782cebc2f75d7c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Scenes/MirrorMultipleMatches.unity + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts.meta new file mode 100644 index 0000000..bc1a9c0 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d418be768b6d32e4d9c3b8828929c3eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs new file mode 100644 index 0000000..7809269 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs @@ -0,0 +1,644 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + public class CanvasController : MonoBehaviour + { + /// + /// Match Controllers listen for this to terminate their match and clean up + /// + public event Action OnPlayerDisconnect; + + /// + /// Cross-reference of client that created the corresponding match in openMatches below + /// + internal static readonly Dictionary playerMatches = new Dictionary(); + + /// + /// Open matches that are available for joining + /// + internal static readonly Dictionary openMatches = new Dictionary(); + + /// + /// Network Connections of all players in a match + /// + internal static readonly Dictionary> matchConnections = new Dictionary>(); + + /// + /// Player informations by Network Connection + /// + internal static readonly Dictionary playerInfos = new Dictionary(); + + /// + /// Network Connections that have neither started nor joined a match yet + /// + internal static readonly List waitingConnections = new List(); + + /// + /// GUID of a match the local player has created + /// + internal Guid localPlayerMatch = Guid.Empty; + + /// + /// GUID of a match the local player has joined + /// + internal Guid localJoinedMatch = Guid.Empty; + + /// + /// GUID of a match the local player has selected in the Toggle Group match list + /// + internal Guid selectedMatch = Guid.Empty; + + // Used in UI for "Player #" + int playerIndex = 1; + + [Header("GUI References")] + public GameObject matchList; + public GameObject matchPrefab; + public GameObject matchControllerPrefab; + public Button createButton; + public Button joinButton; + public GameObject lobbyView; + public GameObject roomView; + public RoomGUI roomGUI; + public ToggleGroup toggleGroup; + + // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void ResetStatics() + { + playerMatches.Clear(); + openMatches.Clear(); + matchConnections.Clear(); + playerInfos.Clear(); + waitingConnections.Clear(); + } + + #region UI Functions + + // Called from several places to ensure a clean reset + // - MatchNetworkManager.Awake + // - OnStartServer + // - OnStartClient + // - OnClientDisconnect + // - ResetCanvas + internal void InitializeData() + { + playerMatches.Clear(); + openMatches.Clear(); + matchConnections.Clear(); + waitingConnections.Clear(); + localPlayerMatch = Guid.Empty; + localJoinedMatch = Guid.Empty; + } + + // Called from OnStopServer and OnStopClient when shutting down + void ResetCanvas() + { + InitializeData(); + lobbyView.SetActive(false); + roomView.SetActive(false); + gameObject.SetActive(false); + } + + #endregion + + #region Button Calls + + /// + /// Called from + /// + /// + [ClientCallback] + public void SelectMatch(Guid matchId) + { + if (matchId == Guid.Empty) + { + selectedMatch = Guid.Empty; + joinButton.interactable = false; + } + else + { + if (!openMatches.Keys.Contains(matchId)) + { + joinButton.interactable = false; + return; + } + + selectedMatch = matchId; + MatchInfo infos = openMatches[matchId]; + joinButton.interactable = infos.players < infos.maxPlayers; + } + } + + /// + /// Assigned in inspector to Create button + /// + [ClientCallback] + public void RequestCreateMatch() + { + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Create }); + } + + /// + /// Assigned in inspector to Cancel button + /// + [ClientCallback] + public void RequestCancelMatch() + { + if (localPlayerMatch == Guid.Empty) return; + + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Cancel }); + } + + /// + /// Assigned in inspector to Join button + /// + [ClientCallback] + public void RequestJoinMatch() + { + if (selectedMatch == Guid.Empty) return; + + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Join, matchId = selectedMatch }); + } + + /// + /// Assigned in inspector to Leave button + /// + [ClientCallback] + public void RequestLeaveMatch() + { + if (localJoinedMatch == Guid.Empty) return; + + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Leave, matchId = localJoinedMatch }); + } + + /// + /// Assigned in inspector to Ready button + /// + [ClientCallback] + public void RequestReadyChange() + { + if (localPlayerMatch == Guid.Empty && localJoinedMatch == Guid.Empty) return; + + Guid matchId = localPlayerMatch == Guid.Empty ? localJoinedMatch : localPlayerMatch; + + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Ready, matchId = matchId }); + } + + /// + /// Assigned in inspector to Start button + /// + [ClientCallback] + public void RequestStartMatch() + { + if (localPlayerMatch == Guid.Empty) return; + + NetworkClient.Send(new ServerMatchMessage { serverMatchOperation = ServerMatchOperation.Start }); + } + + /// + /// Called from + /// + [ClientCallback] + public void OnMatchEnded() + { + localPlayerMatch = Guid.Empty; + localJoinedMatch = Guid.Empty; + ShowLobbyView(); + } + + #endregion + + #region Server & Client Callbacks + + // Methods in this section are called from MatchNetworkManager's corresponding methods + + [ServerCallback] + internal void OnStartServer() + { + InitializeData(); + NetworkServer.RegisterHandler(OnServerMatchMessage); + } + + [ServerCallback] + internal void OnServerReady(NetworkConnectionToClient conn) + { + waitingConnections.Add(conn); + playerInfos.Add(conn, new PlayerInfo { playerIndex = this.playerIndex, ready = false }); + playerIndex++; + + SendMatchList(); + } + + [ServerCallback] + internal IEnumerator OnServerDisconnect(NetworkConnectionToClient conn) + { + // Invoke OnPlayerDisconnect on all instances of MatchController + OnPlayerDisconnect?.Invoke(conn); + + if (playerMatches.TryGetValue(conn, out Guid matchId)) + { + playerMatches.Remove(conn); + openMatches.Remove(matchId); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + { + PlayerInfo _playerInfo = playerInfos[playerConn]; + _playerInfo.ready = false; + _playerInfo.matchId = Guid.Empty; + playerInfos[playerConn] = _playerInfo; + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + } + + foreach (KeyValuePair> kvp in matchConnections) + kvp.Value.Remove(conn); + + PlayerInfo playerInfo = playerInfos[conn]; + if (playerInfo.matchId != Guid.Empty) + { + if (openMatches.TryGetValue(playerInfo.matchId, out MatchInfo matchInfo)) + { + matchInfo.players--; + openMatches[playerInfo.matchId] = matchInfo; + } + + HashSet connections; + if (matchConnections.TryGetValue(playerInfo.matchId, out connections)) + { + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnectionToClient playerConn in matchConnections[playerInfo.matchId]) + if (playerConn != conn) + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + } + + SendMatchList(); + + yield return null; + } + + [ServerCallback] + internal void OnStopServer() + { + ResetCanvas(); + } + + [ClientCallback] + internal void OnStartClient() + { + InitializeData(); + ShowLobbyView(); + createButton.gameObject.SetActive(true); + joinButton.gameObject.SetActive(true); + NetworkClient.RegisterHandler(OnClientMatchMessage); + } + + [ClientCallback] + internal void OnClientDisconnect() + { + InitializeData(); + } + + [ClientCallback] + internal void OnStopClient() + { + ResetCanvas(); + } + + #endregion + + #region Server Match Message Handlers + + [ServerCallback] + void OnServerMatchMessage(NetworkConnectionToClient conn, ServerMatchMessage msg) + { + switch (msg.serverMatchOperation) + { + case ServerMatchOperation.None: + { + Debug.LogWarning("Missing ServerMatchOperation"); + break; + } + case ServerMatchOperation.Create: + { + OnServerCreateMatch(conn); + break; + } + case ServerMatchOperation.Cancel: + { + OnServerCancelMatch(conn); + break; + } + case ServerMatchOperation.Join: + { + OnServerJoinMatch(conn, msg.matchId); + break; + } + case ServerMatchOperation.Leave: + { + OnServerLeaveMatch(conn, msg.matchId); + break; + } + case ServerMatchOperation.Ready: + { + OnServerPlayerReady(conn, msg.matchId); + break; + } + case ServerMatchOperation.Start: + { + OnServerStartMatch(conn); + break; + } + } + } + + [ServerCallback] + void OnServerCreateMatch(NetworkConnectionToClient conn) + { + if (playerMatches.ContainsKey(conn)) return; + + Guid newMatchId = Guid.NewGuid(); + matchConnections.Add(newMatchId, new HashSet()); + matchConnections[newMatchId].Add(conn); + playerMatches.Add(conn, newMatchId); + openMatches.Add(newMatchId, new MatchInfo { matchId = newMatchId, maxPlayers = 2, players = 1 }); + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = newMatchId; + playerInfos[conn] = playerInfo; + + PlayerInfo[] infos = matchConnections[newMatchId].Select(playerConn => playerInfos[playerConn]).ToArray(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Created, matchId = newMatchId, playerInfos = infos }); + + SendMatchList(); + } + + [ServerCallback] + void OnServerCancelMatch(NetworkConnectionToClient conn) + { + if (!playerMatches.ContainsKey(conn)) return; + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Cancelled }); + + Guid matchId; + if (playerMatches.TryGetValue(conn, out matchId)) + { + playerMatches.Remove(conn); + openMatches.Remove(matchId); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + { + PlayerInfo playerInfo = playerInfos[playerConn]; + playerInfo.ready = false; + playerInfo.matchId = Guid.Empty; + playerInfos[playerConn] = playerInfo; + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + + SendMatchList(); + } + } + + [ServerCallback] + void OnServerJoinMatch(NetworkConnectionToClient conn, Guid matchId) + { + if (!matchConnections.ContainsKey(matchId) || !openMatches.ContainsKey(matchId)) return; + + MatchInfo matchInfo = openMatches[matchId]; + matchInfo.players++; + openMatches[matchId] = matchInfo; + matchConnections[matchId].Add(conn); + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = matchId; + playerInfos[conn] = playerInfo; + + PlayerInfo[] infos = matchConnections[matchId].Select(playerConn => playerInfos[playerConn]).ToArray(); + SendMatchList(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Joined, matchId = matchId, playerInfos = infos }); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + + [ServerCallback] + void OnServerLeaveMatch(NetworkConnectionToClient conn, Guid matchId) + { + MatchInfo matchInfo = openMatches[matchId]; + matchInfo.players--; + openMatches[matchId] = matchInfo; + + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = false; + playerInfo.matchId = Guid.Empty; + playerInfos[conn] = playerInfo; + + foreach (KeyValuePair> kvp in matchConnections) + kvp.Value.Remove(conn); + + HashSet connections = matchConnections[matchId]; + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + + SendMatchList(); + + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Departed }); + } + + [ServerCallback] + void OnServerPlayerReady(NetworkConnectionToClient conn, Guid matchId) + { + PlayerInfo playerInfo = playerInfos[conn]; + playerInfo.ready = !playerInfo.ready; + playerInfos[conn] = playerInfo; + + HashSet connections = matchConnections[matchId]; + PlayerInfo[] infos = connections.Select(playerConn => playerInfos[playerConn]).ToArray(); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.UpdateRoom, playerInfos = infos }); + } + + [ServerCallback] + void OnServerStartMatch(NetworkConnectionToClient conn) + { + if (!playerMatches.ContainsKey(conn)) return; + + Guid matchId; + if (playerMatches.TryGetValue(conn, out matchId)) + { + GameObject matchControllerObject = Instantiate(matchControllerPrefab); + matchControllerObject.GetComponent().matchId = matchId; + NetworkServer.Spawn(matchControllerObject); + + MatchController matchController = matchControllerObject.GetComponent(); + + foreach (NetworkConnectionToClient playerConn in matchConnections[matchId]) + { + playerConn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.Started }); + + GameObject player = Instantiate(NetworkManager.singleton.playerPrefab); + player.GetComponent().matchId = matchId; + NetworkServer.AddPlayerForConnection(playerConn, player); + + if (matchController.player1 == null) + matchController.player1 = playerConn.identity; + else + matchController.player2 = playerConn.identity; + + /* Reset ready state for after the match. */ + PlayerInfo playerInfo = playerInfos[playerConn]; + playerInfo.ready = false; + playerInfos[playerConn] = playerInfo; + } + + matchController.startingPlayer = matchController.player1; + matchController.currentPlayer = matchController.player1; + + playerMatches.Remove(conn); + openMatches.Remove(matchId); + matchConnections.Remove(matchId); + SendMatchList(); + + OnPlayerDisconnect += matchController.OnPlayerDisconnect; + } + } + + /// + /// Sends updated match list to all waiting connections or just one if specified + /// + /// + [ServerCallback] + internal void SendMatchList(NetworkConnectionToClient conn = null) + { + if (conn != null) + conn.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); + else + foreach (NetworkConnectionToClient waiter in waitingConnections) + waiter.Send(new ClientMatchMessage { clientMatchOperation = ClientMatchOperation.List, matchInfos = openMatches.Values.ToArray() }); + } + + #endregion + + #region Client Match Message Handler + + [ClientCallback] + void OnClientMatchMessage(ClientMatchMessage msg) + { + switch (msg.clientMatchOperation) + { + case ClientMatchOperation.None: + { + Debug.LogWarning("Missing ClientMatchOperation"); + break; + } + case ClientMatchOperation.List: + { + openMatches.Clear(); + foreach (MatchInfo matchInfo in msg.matchInfos) + openMatches.Add(matchInfo.matchId, matchInfo); + + RefreshMatchList(); + break; + } + case ClientMatchOperation.Created: + { + localPlayerMatch = msg.matchId; + ShowRoomView(); + roomGUI.RefreshRoomPlayers(msg.playerInfos); + roomGUI.SetOwner(true); + break; + } + case ClientMatchOperation.Cancelled: + { + localPlayerMatch = Guid.Empty; + ShowLobbyView(); + break; + } + case ClientMatchOperation.Joined: + { + localJoinedMatch = msg.matchId; + ShowRoomView(); + roomGUI.RefreshRoomPlayers(msg.playerInfos); + roomGUI.SetOwner(false); + break; + } + case ClientMatchOperation.Departed: + { + localJoinedMatch = Guid.Empty; + ShowLobbyView(); + break; + } + case ClientMatchOperation.UpdateRoom: + { + roomGUI.RefreshRoomPlayers(msg.playerInfos); + break; + } + case ClientMatchOperation.Started: + { + lobbyView.SetActive(false); + roomView.SetActive(false); + break; + } + } + } + + [ClientCallback] + void ShowLobbyView() + { + lobbyView.SetActive(true); + roomView.SetActive(false); + + foreach (Transform child in matchList.transform) + if (child.gameObject.GetComponent().GetMatchId() == selectedMatch) + { + Toggle toggle = child.gameObject.GetComponent(); + toggle.isOn = true; + } + } + + [ClientCallback] + void ShowRoomView() + { + lobbyView.SetActive(false); + roomView.SetActive(true); + } + + [ClientCallback] + void RefreshMatchList() + { + foreach (Transform child in matchList.transform) + Destroy(child.gameObject); + + joinButton.interactable = false; + + foreach (MatchInfo matchInfo in openMatches.Values) + { + GameObject newMatch = Instantiate(matchPrefab, Vector3.zero, Quaternion.identity); + newMatch.transform.SetParent(matchList.transform, false); + newMatch.GetComponent().SetMatchInfo(matchInfo); + + Toggle toggle = newMatch.GetComponent(); + toggle.group = toggleGroup; + if (matchInfo.matchId == selectedMatch) + toggle.isOn = true; + } + } + + #endregion + } +} diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta new file mode 100644 index 0000000..feeb6b1 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c12d7cb6cdb799041927819f22a2c931 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Scripts/CanvasController.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs new file mode 100644 index 0000000..9fa6011 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + public class CellGUI : MonoBehaviour + { + public MatchController matchController; + public CellValue cellValue; + + [Header("GUI References")] + public Image image; + public Button button; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] internal NetworkIdentity playerIdentity; + + public void Awake() + { + matchController.MatchCells.Add(cellValue, this); + } + + [ClientCallback] + public void MakePlay() + { + if (matchController.currentPlayer.isLocalPlayer) + matchController.CmdMakePlay(cellValue); + } + + [ClientCallback] + public void SetPlayer(NetworkIdentity playerIdentity) + { + if (playerIdentity != null) + { + this.playerIdentity = playerIdentity; + image.color = this.playerIdentity.isLocalPlayer ? Color.blue : Color.red; + button.interactable = false; + } + else + { + this.playerIdentity = null; + image.color = Color.white; + button.interactable = true; + } + } + } +} \ No newline at end of file diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta new file mode 100644 index 0000000..691c6ef --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 9cda2a394a443474689a3c6d6044f7b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 129321 + packageName: Mirror + packageVersion: 96.0.1 + assetPath: Assets/Mirror/Examples/MultipleMatches/Scripts/CellGUI.cs + uploadId: 736421 diff --git a/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs b/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs new file mode 100644 index 0000000..afe1dd8 --- /dev/null +++ b/Assets/Mirror/Examples/MultipleMatches/Scripts/MatchController.cs @@ -0,0 +1,312 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace Mirror.Examples.MultipleMatch +{ + [RequireComponent(typeof(NetworkMatch))] + public class MatchController : NetworkBehaviour + { + internal readonly SyncDictionary matchPlayerData = new SyncDictionary(); + internal readonly Dictionary MatchCells = new Dictionary(); + + CellValue boardScore = CellValue.None; + bool playAgain = false; + + [Header("GUI References")] + public CanvasGroup canvasGroup; + public Text gameText; + public Button exitButton; + public Button playAgainButton; + public Text winCountLocal; + public Text winCountOpponent; + + [Header("Diagnostics")] + [ReadOnly, SerializeField] internal CanvasController canvasController; + [ReadOnly, SerializeField] internal NetworkIdentity player1; + [ReadOnly, SerializeField] internal NetworkIdentity player2; + [ReadOnly, SerializeField] internal NetworkIdentity startingPlayer; + + [SyncVar(hook = nameof(UpdateGameUI))] + [ReadOnly, SerializeField] internal NetworkIdentity currentPlayer; + + void Awake() + { +#if UNITY_2022_2_OR_NEWER + canvasController = GameObject.FindAnyObjectByType(); +#else + // Deprecated in Unity 2023.1 + canvasController = GameObject.FindObjectOfType(); +#endif + } + + public override void OnStartServer() + { + StartCoroutine(AddPlayersToMatchController()); + } + + // For the SyncDictionary to properly fire the update callback, we must + // wait a frame before adding the players to the already spawned MatchController + IEnumerator AddPlayersToMatchController() + { + yield return null; + + matchPlayerData.Add(player1, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player1.connectionToClient].playerIndex }); + matchPlayerData.Add(player2, new MatchPlayerData { playerIndex = CanvasController.playerInfos[player2.connectionToClient].playerIndex }); + } + + public override void OnStartClient() + { + canvasGroup.alpha = 1f; + canvasGroup.interactable = true; + canvasGroup.blocksRaycasts = true; + + exitButton.gameObject.SetActive(false); + playAgainButton.gameObject.SetActive(false); + + // Assign handler for SyncDictionary changes + matchPlayerData.OnChange = UpdateWins; + } + + [ClientCallback] + public void UpdateGameUI(NetworkIdentity _, NetworkIdentity newPlayerTurn) + { + if (!newPlayerTurn) return; + + if (newPlayerTurn.gameObject.GetComponent().isLocalPlayer) + { + gameText.text = "Your Turn"; + gameText.color = Color.blue; + } + else + { + gameText.text = "Their Turn"; + gameText.color = Color.red; + } + } + + [ClientCallback] + public void UpdateWins(SyncDictionary.Operation op, NetworkIdentity key, MatchPlayerData matchPlayerData) + { + if (key.gameObject.GetComponent().isLocalPlayer) + winCountLocal.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}"; + else + winCountOpponent.text = $"Player {matchPlayerData.playerIndex}\n{matchPlayerData.wins}"; + } + + [Command(requiresAuthority = false)] + public void CmdMakePlay(CellValue cellValue, NetworkConnectionToClient sender = null) + { + // If wrong player or cell already taken, ignore + if (sender.identity != currentPlayer || MatchCells[cellValue].playerIdentity != null) + return; + + MatchCells[cellValue].playerIdentity = currentPlayer; + RpcUpdateCell(cellValue, currentPlayer); + + MatchPlayerData mpd = matchPlayerData[currentPlayer]; + mpd.currentScore = mpd.currentScore | cellValue; + matchPlayerData[currentPlayer] = mpd; + + boardScore |= cellValue; + + if (CheckWinner(mpd.currentScore)) + { + mpd.wins += 1; + matchPlayerData[currentPlayer] = mpd; + RpcShowWinner(currentPlayer); + currentPlayer = null; + } + else if (boardScore == CellValue.Full) + { + RpcShowWinner(null); + currentPlayer = null; + } + else + { + // Set currentPlayer SyncVar so clients know whose turn it is + currentPlayer = currentPlayer == player1 ? player2 : player1; + } + + } + + [ServerCallback] + bool CheckWinner(CellValue currentScore) + { + if ((currentScore & CellValue.TopRow) == CellValue.TopRow) + return true; + if ((currentScore & CellValue.MidRow) == CellValue.MidRow) + return true; + if ((currentScore & CellValue.BotRow) == CellValue.BotRow) + return true; + if ((currentScore & CellValue.LeftCol) == CellValue.LeftCol) + return true; + if ((currentScore & CellValue.MidCol) == CellValue.MidCol) + return true; + if ((currentScore & CellValue.RightCol) == CellValue.RightCol) + return true; + if ((currentScore & CellValue.Diag1) == CellValue.Diag1) + return true; + if ((currentScore & CellValue.Diag2) == CellValue.Diag2) + return true; + + return false; + } + + [ClientRpc] + public void RpcUpdateCell(CellValue cellValue, NetworkIdentity player) + { + MatchCells[cellValue].SetPlayer(player); + } + + [ClientRpc] + public void RpcShowWinner(NetworkIdentity winner) + { + foreach (CellGUI cellGUI in MatchCells.Values) + cellGUI.GetComponent

hO&=*dM5!4|nH_*UqusK0MWz`|9B?FI1flz2Qk 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