diff --git a/CMakeLists.txt b/CMakeLists.txt index 74ed7099..cff15afa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,14 +31,6 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(glm) -# FastNoise -FetchContent_Declare( - fastnoise - GIT_REPOSITORY https://github.com/Auburn/FastNoiseLite.git - GIT_TAG master -) -FetchContent_MakeAvailable(fastnoise) - # stb_image FetchContent_Declare( stb @@ -268,7 +260,6 @@ target_include_directories(ft_minecraft PRIVATE ${CMAKE_SOURCE_DIR}/include/shared/Mobs ${CMAKE_SOURCE_DIR}/include/shared/Inventories ${glm_SOURCE_DIR} - ${fastnoise_SOURCE_DIR}/Cpp ${glad_SOURCE_DIR}/include ${stb_SOURCE_DIR} ${zstd_SOURCE_DIR}/lib @@ -302,7 +293,6 @@ target_include_directories(ft_minecraft_server PRIVATE ${CMAKE_SOURCE_DIR}/include/shared/Mobs ${CMAKE_SOURCE_DIR}/include/shared/Inventories ${glm_SOURCE_DIR} - ${fastnoise_SOURCE_DIR}/Cpp ${zstd_SOURCE_DIR}/lib ) # Should look into restructure stuff so we can remove glad from server diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000..5415933a --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,33 @@ +ft_minecraft โ€” Pimp My World +Copyright (C) 2026 Leonard Skraber +Copyright (C) 2026 Lucas Dominique + +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 . + +---------------------------------------------------------------------- + +Note on bundled assets: + +The source code of ft_minecraft is licensed under the GNU AGPLv3 (see LICENSE). +The assets shipped under assets/ are NOT covered by the AGPLv3 and remain +the property of their respective authors. They are used here for +non-commercial, educational purposes within the scope of the 42 school +project. See the "Credits & Assets" section of README.md for details: + + - Music: patrickdearteaga.com + - SFX: Mojang Studios (Minecraft) + - Textures: 16x C-Tetra, Alternate Ingots, Minetest Game default textures + +Anyone redistributing this project should review the licensing terms of +each asset source before bundling them. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..be3f7b28 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + 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. + + + Copyright (C) + + 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 b/README deleted file mode 100644 index cff2c18a..00000000 --- a/README +++ /dev/null @@ -1,13 +0,0 @@ -Required GLFW dependencies for Wayland and X11: -(https://www.glfw.org/docs/latest/compile_guide.html#compile_deps_wayland) - -sudo apt install libwayland-dev libxkbcommon-dev xorg-dev - - -Run: - -mkdir build -cd build -cmake .. -make -./ft_minecraft [optional__seed] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..1377876f --- /dev/null +++ b/README.md @@ -0,0 +1,273 @@ +
+ +ft_minecraft + +# ft_minecraft + +### *Pimp My World* - a voxel sandbox written from scratch in C++ & OpenGL + +[![C++20](https://img.shields.io/badge/C%2B%2B-20-00599C?logo=c%2B%2B&logoColor=white)](https://en.cppreference.com/w/cpp/20) +[![OpenGL](https://img.shields.io/badge/OpenGL-4.6-5586A4?logo=opengl&logoColor=white)](https://www.opengl.org/) +[![CMake](https://img.shields.io/badge/CMake-3.22%2B-064F8C?logo=cmake&logoColor=white)](https://cmake.org/) +[![Platform](https://img.shields.io/badge/Platform-Linux%20%7C%20Windows-lightgrey)]() +[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](LICENSE) + +
+ +--- + +## โœจ Overview + +**ft_minecraft** is a from-scratch voxel engine inspired by Minecraft, built as the +follow-up to the *ft_vox* project at 42. The emphasis is on **procedural generation** +and **rendering quality** - building a world that looks good, runs smoothly, and is +fun to explore alone or with friends over the network. + +Everything from terrain generation to lighting, shadows and chunk meshing is implemented +by hand. Only thin third-party libraries are used (windowing, image loading, audio +playback, fonts, math). + +## ๐Ÿš€ Features + +### ๐ŸŒ Procedural world +- **16 biomes** with smooth transitions: Plains, Desert, Red Desert, Dark Forest, + Birch Forest, Jungle, Savanna, Mesa, Mountain, Tundra, Ice Plains, Swamp, + Ocean, Mushroom Island, Volcanic, Nether. +- Per-biome geography, elevation, vegetation and color palette. +- Procedurally-generated trees with varying shape, height, width and leaf density. +- Small plants, flowers, tall grass and mushrooms scattered throughout the world. +- Lakes and **meandering rivers** carved across the surface. +- **Realistic water simulation** - dynamic flow and spreading: place a + water source and the liquid propagates, fills depressions and pours off ledges + in real time. +- **Worm-style cave systems** with natural cave entrances, and **clustered ores** + (coal, iron, gold, diamondโ€ฆ). +- **Persistent chunks**: blocks you break or place stay broken/placed across + unload/reload, and are synchronized in multiplayer. +- Chunks are generated and meshed **on demand** as the player moves - only the + chunks within view get built, and they're released again when far enough away, + so the world is effectively infinite without baking it all up-front. +- Navigable over the 5,000,000-block XZ requirement. + +### ๐ŸŽจ Rendering +- Custom OpenGL 4.6 renderer with a deferred-style **G-Buffer**. +- **Directional sun lighting** with **Cascaded Shadow Maps** (CSM) and alpha-tested + shadow casters for leaves/vegetation. +- **Screen-Space Ambient Occlusion** (SSAO) with blur pass. +- **Volumetric 3D clouds** rendered via a dedicated shader and composited. +- **Procedural sky** with a precomputed **Sky LUT** (atmospheric scattering style). +- **Transparent water** with reflection/refraction framebuffers, DuDv normal-mapped + waves and underwater caustics. +- **Underwater post-effect**: color tint and reduced visibility when the camera + is submerged. +- **Far-distance fog** for immersion. +- **Auto-exposure** (luminance reduction) for HDR-like tone mapping. +- **Bit-packed vertex format** for a lean GPU footprint, plus view-frustum culling. + +### ๐ŸŽฎ Gameplay +- First-person camera, mouse look (full 360ยฐ Y axis), WASD movement, jump, sprint, + sneak, and a **fly / spectator mode** (ร—20 speed). +- **Gravity & block collisions**, swimming/diving in water with optional slowed + movement. +- **Break / place blocks** with raycasting; picked-up blocks go into the inventory. +- **Hotbar + full inventory UI** with drag-and-drop, stacking and a hand slot. +- **Crafting system** with crafting station / recipes. +- **Item entities** (block drops) you can pick up. +- **Hostile mobs**: zombies and creepers that spawn around the player and chase + on approach, with their own animations and skins. +- Basic walking and attacking animations for the player. + +### ๐Ÿ”Š Audio (SoLoud) +- Per-biome **ambient music** with smooth cross-fades between biomes. +- Player & mob sounds: footsteps (per-material), attacking, swimming, block + break/place, liquid SFX. +- Distance-attenuated, stereo positional audio. +- In-game **sound menu** to balance master / music / SFX volumes. + +### ๐ŸŒ Multiplayer +- Custom **UDP client/server** (`ft_minecraft` โ†” `ft_minecraft_server`). +- World is **generated on the server** and streamed to clients on demand + (with zstd compression for chunk payloads). +- 4+ players supported, with synchronized: + - block placement / destruction (persistent on the server), + - mob spawns and entity states, + - player positions, animations and actions. +- In-game **chat** and **player list** HUD. + +### ๐Ÿ–ฅ๏ธ Interface +- Main menu, pause menu, multiplayer menu, settings menu (controls / graphics / + sounds) - all rendered with FreeType + a custom GUI renderer. +- **Debug HUD** (toggleable): FPS, triangle count, cube count, chunk count, + player position, biome, etc. +- Chunk-boundary debug overlay and a wireframe / hitbox renderer. +- Configurable controls and graphics settings (render distance, etc.). +- **Dev tweaks panel** (Dear ImGui). + +## ๐Ÿ“ธ Screenshots + +
+ +| | | +|:-:|:-:| +| ![Biomes transition](assets/screenshots/biomes.png) | ![Trees & vegetation](assets/screenshots/vegetation.png) | +| *Smooth biome transitions* | *Procedurally generated trees* | +| ![Rivers & lakes](assets/screenshots/water.png) | ![Caves & ores](assets/screenshots/caves.png) | +| *Rivers, lakes and transparent water* | *Cave systems with ore clusters* | +| ![Shadows & SSAO](assets/screenshots/lighting.png) | ![Sky & clouds](assets/screenshots/sky.png) | +| *Directional lighting, shadows, SSAO* | *Volumetric clouds and procedural sky* | +| ![Multiplayer](assets/screenshots/multiplayer.png) | ![Inventory & crafting](assets/screenshots/inventory.png) | +| *Multiplayer session* | *Inventory and crafting UI* | + +
+ +## ๐Ÿ› ๏ธ Build & Run + +### Dependencies + +The project uses CMake `FetchContent` to pull most dependencies automatically +(GLFW, GLAD, GLM, stb, ImGui, zstd, FreeType, SoLoud). You only +need a recent toolchain and the system libraries GLFW needs for Wayland/X11: + +```bash +# Ubuntu / Debian +sudo apt install build-essential cmake git \ + libwayland-dev libxkbcommon-dev xorg-dev +``` + +> Requires a C++20 compiler and an OpenGL **4.6**-capable GPU. + +### Build + +A one-liner is provided: + +```bash +./build.sh +``` + +Or the manual equivalent: + +```bash +mkdir -p build && cd build +cmake .. +make -j$(nproc) +``` + +This produces two executables in `build/`: + +| Binary | Role | +|---|---| +| `ft_minecraft` | Game client (window, rendering, input) | +| `ft_minecraft_server` | Standalone dedicated server | + +### Run + +**Singleplayer / connect to a local server:** + +```bash +# Terminal 1 - start the server (optional seed) +./ft_minecraft_server [seed] + +# Terminal 2 - start the client +./ft_minecraft +``` + +The client can also connect to a remote server through the multiplayer menu. + +## ๐ŸŽฎ Default controls + +| Action | Key | +|---|---| +| Move | `W` `A` `S` `D` | +| Jump / fly up | `Space` | +| Sneak / fly down | `Left Shift` | +| Sprint | `Left Ctrl` | +| Drop item | `Q` | +| Hotbar slot | `1` โ€“ `9` | +| Inventory | `E` | +| Chat / commands | `T` / `Enter` | +| Hide HUD | `F2` | +| Debug HUD | `F3` | +| Dev ImGui overlay | `F6` | +| Pause / menu | `Esc` | + +Most keys are rebindable from the in-game **Settings โ†’ Controls** menu. +**Fly mode** can be toggled from the ImGui dev overlay (`F6`), from the +in-game settings tab, or with the chat command `/gamemode spectator`. + +## ๐Ÿ“‚ Project layout + +``` +ft_minecraft/ +โ”œโ”€โ”€ assets/ # textures, sounds, skins, videos +โ”œโ”€โ”€ fonts/ # TTF fonts used by the GUI +โ”œโ”€โ”€ shaders/ # all GLSL shaders (sky, water, SSAO, CSM, clouds, โ€ฆ) +โ”œโ”€โ”€ include/ +โ”‚ โ”œโ”€โ”€ client/ # renderer, menus, characters, items, audio +โ”‚ โ”œโ”€โ”€ server/ # world, chunk generation, server loop +โ”‚ โ””โ”€โ”€ shared/ # protocol, chunk format, entities, mobs, inventories +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ client/ # OpenGL client implementation +โ”‚ โ”œโ”€โ”€ server/ # dedicated server implementation +โ”‚ โ””โ”€โ”€ shared/ # code shared between client and server +โ”œโ”€โ”€ CMakeLists.txt +โ”œโ”€โ”€ build.sh +โ””โ”€โ”€ en.subject.pdf # 42 subject (Pimp My World) +``` + +## ๐Ÿงฑ Tech stack + +| Area | Library / tech | +|---|---| +| Language | C++20 | +| Build | CMake 3.22 + FetchContent | +| Windowing / input | GLFW | +| GPU API | OpenGL 4.6 (via GLAD) | +| Math | GLM | +| Image loading | stb_image | +| Dev tools | Dear ImGui (runtime tweaks) | +| Menus / text | FreeType + custom GUI renderer | +| Audio | SoLoud (MiniAudio backend) | +| Compression | zstd (chunk payloads) | +| Networking | Raw UDP sockets (BSD / Winsock) | + +## ๐Ÿ™ Credits & Assets + +This project bundles third-party assets - all credit to their original authors. + +**Music** +- [patrickdearteaga.com](https://patrickdearteaga.com) - biome ambient tracks. + +**Sound effects** +- Mojang Studios (Minecraft SFX). + +**Texture packs** +- [16x C-Tetra (1.13)](https://www.planetminecraft.com/texture-pack/16x-c-tetra-1-13/) - Textures. +- [Alternate Ingots](https://modrinth.com/resourcepack/alternate-ingots?version=1.20) - Ingots. +- [Minetest Game - `default` textures](https://github.com/luanti-org/minetest_game/tree/master/mods/default/textures) - Tools & more. + +All assets remain the property of their respective authors and are used here +for non-commercial, educational purposes within the scope of the 42 school +project. + +## ๐Ÿ“œ License + +The **source code** of ft_minecraft is licensed under the +**GNU Affero General Public License v3.0** โ€” see [LICENSE](LICENSE) and +[COPYRIGHT](COPYRIGHT). + +> In short: you may use, study, modify and redistribute this code, including +> over a network, **provided that** any modified version you distribute (or +> make available to users over a network) is also released under the AGPLv3 +> with its full source code. + +The **bundled assets** in `assets/` (music, sound effects, textures) are +**not** covered by the AGPLv3 โ€” they remain the property of their respective +authors and are used here under their own terms for non-commercial, +educational purposes (see [Credits & Assets](#-credits--assets)). + +## ๐Ÿ‘ฅ Authors + +- **Leonard Skraber** - `lskraber@student.42lausanne.ch` +- **Lucas Dominique** - `ldominiq@student.42lausanne.ch` + +> 42 Lausanne diff --git a/assets/screenshots/biomes.png b/assets/screenshots/biomes.png new file mode 100644 index 00000000..11fd8949 Binary files /dev/null and b/assets/screenshots/biomes.png differ diff --git a/assets/screenshots/caves.png b/assets/screenshots/caves.png new file mode 100644 index 00000000..e7c0945a Binary files /dev/null and b/assets/screenshots/caves.png differ diff --git a/assets/screenshots/inventory.png b/assets/screenshots/inventory.png new file mode 100644 index 00000000..ab2275d5 Binary files /dev/null and b/assets/screenshots/inventory.png differ diff --git a/assets/screenshots/lighting.png b/assets/screenshots/lighting.png new file mode 100644 index 00000000..597fea62 Binary files /dev/null and b/assets/screenshots/lighting.png differ diff --git a/assets/screenshots/multiplayer.png b/assets/screenshots/multiplayer.png new file mode 100644 index 00000000..1d0d9f28 Binary files /dev/null and b/assets/screenshots/multiplayer.png differ diff --git a/assets/screenshots/sky.png b/assets/screenshots/sky.png new file mode 100644 index 00000000..9f7cd411 Binary files /dev/null and b/assets/screenshots/sky.png differ diff --git a/assets/screenshots/vegetation.png b/assets/screenshots/vegetation.png new file mode 100644 index 00000000..67c95f5e Binary files /dev/null and b/assets/screenshots/vegetation.png differ diff --git a/assets/screenshots/water.png b/assets/screenshots/water.png new file mode 100644 index 00000000..f40d13f1 Binary files /dev/null and b/assets/screenshots/water.png differ diff --git a/doc b/doc deleted file mode 100644 index 26dcdafa..00000000 --- a/doc +++ /dev/null @@ -1,7 +0,0 @@ -# CHUNK GENERATION - -## Steps: - - 1. World creates and keeps track of chunks (calling constructor). - 2. Chunk constructor calls **GENERATE()** function. - 2. Once all adjecent chunks are generated, World calls **updateChunk()** on chunk. Which renders it. \ No newline at end of file diff --git a/include/client/AudioManager.hpp b/include/client/AudioManager.hpp index 4430e75d..296871cb 100644 --- a/include/client/AudioManager.hpp +++ b/include/client/AudioManager.hpp @@ -85,7 +85,7 @@ class AudioManager { void shutdown(); // Per-frame: drives 3D listener, biome music crossfade, footsteps, mob audio. - // `isPlaying` mirrors App::GameState::Playing โ€” false suspends music + mutes triggers. + // `isPlaying` mirrors App::GameState::Playing - false suspends music + mutes triggers. void update(float deltaTime, bool isPlaying, Camera& cam, Renderer& world); // Switch ambient music. Crossfades over ~3s @@ -170,7 +170,7 @@ class AudioManager { // ---- listener-jump detection ------------------------------------------ // Player respawn / debug teleport moves the listener in a single frame. Active 3D voices // (especially long ones like the creeper fuse) keep playing at their absolute world coords, - // and SoLoud's spatializer recomputes their pan/volume against the new listener โ€” the + // and SoLoud's spatializer recomputes their pan/volume against the new listener - the // result is an audible click/glitch on the next buffer. Tracking the listener position // lets us detect that jump and stop the long-running 3D voices we own. glm::dvec3 prevListenerPos{0.0}; @@ -197,7 +197,7 @@ class AudioManager { glm::dvec3 lastPos{}; // last seen position, used for 3D death/explode sfx // Position of the most recently consumed snapshot. We compute footstep deltas from THIS, // not from snapshots[size-2], because Renderer.cpp wipes & reseeds the snapshots vector - // whenever there's a >100ms server-side gap โ€” losing the first move-after-idle every + // whenever there's a >100ms server-side gap - losing the first move-after-idle every // stop/go cycle (chaseโ†’attackโ†’chase). Caching it here survives the reseed. glm::dvec3 lastConsumedPos{}; bool hasLastConsumedPos = false; @@ -216,7 +216,7 @@ class AudioManager { // prevPrimed before, which mis-fired when a primed creeper got killed mid-fuse). bool diedByExplosion = false; // SoLoud voice for the active creeper fuse one-shot. Tracked so we can stop it on - // unprime / death / explode โ€” otherwise the sample keeps playing at the creeper's old + // unprime / death / explode - otherwise the sample keeps playing at the creeper's old // position and glitches when the listener jumps (player death + respawn far away). SoLoud::handle fuseHandle = 0; // Set when the packet handler fires a death sfx; sweep skips it to avoid double-firing. diff --git a/include/client/AutoExposure.hpp b/include/client/AutoExposure.hpp index 4aa5e670..72fe2985 100644 --- a/include/client/AutoExposure.hpp +++ b/include/client/AutoExposure.hpp @@ -15,7 +15,7 @@ class Shader; // - call submit() each frame AFTER sceneFBO->resolve() and BEFORE the // cloud composite (the resolved color is what we meter on) // - call update(dt, currentExposure) to get the new smoothed exposure -// (will be 1 frame behind submit() โ€” which is fine and free) +// (will be 1 frame behind submit() - which is fine and free) class AutoExposure { public: AutoExposure(); diff --git a/include/client/ChunkRenderer.hpp b/include/client/ChunkRenderer.hpp index d4e18d41..8604ab9b 100644 --- a/include/client/ChunkRenderer.hpp +++ b/include/client/ChunkRenderer.hpp @@ -98,13 +98,13 @@ class ChunkRenderer : public Chunk { // alpha test. Switching modes only affects the *next* mesh rebuild; for // instant effect call buildMesh() on every loaded chunk (or press F3+A). // - // Fast โ€” leaves treated as opaque blocks. Mesher culls leaf-to-leaf + // Fast - leaves treated as opaque blocks. Mesher culls leaf-to-leaf // and solid-to-leaf faces. Fragment shader skips alpha test. // Cheapest; leaves look like solid green cubes. - // Fancy โ€” leaves treated as transparent (original behaviour). Every + // Fancy - leaves treated as transparent (original behaviour). Every // face emitted, including leaves seen through other leaves. // Most expensive; visually richest. - // Smart โ€” leaves alpha-tested (cutouts visible on outer faces) but + // Smart - leaves alpha-tested (cutouts visible on outer faces) but // mesher culls like Fast. Outer surface looks like leaves; // inside each canopy is hollow. enum class LeafRenderMode { Fast, Fancy, Smart }; diff --git a/include/client/GBuffer.hpp b/include/client/GBuffer.hpp index 7bb15ddd..49c02bd8 100644 --- a/include/client/GBuffer.hpp +++ b/include/client/GBuffer.hpp @@ -23,7 +23,7 @@ class GBuffer { GLuint fbo = 0; // Framebuffer object GLuint gPosition = 0; - GLuint gNormal = 0; // RGB16F โ€” view-space normal + GLuint gNormal = 0; // RGB16F - view-space normal GLuint depthTexture = 0; // depth texture (sampleable, replaces renderbuffer) int SCR_WIDTH = 0; diff --git a/include/client/HeldItemRenderer.hpp b/include/client/HeldItemRenderer.hpp index b90ee73d..6aabcc35 100644 --- a/include/client/HeldItemRenderer.hpp +++ b/include/client/HeldItemRenderer.hpp @@ -29,7 +29,7 @@ class Character; // heldItemType of 0, BlockType::BEGIN, or BlockType::AIR all mean "nothing // held" and skip rendering for that entity. class HeldItemRenderer { - static constexpr int FLOATS_PER_VERT = 8; // pos(3) + uv(2) + texLayer(1) + skyLight(1) + blockLight(1) โ€” matches cubePropShader.vert + static constexpr int FLOATS_PER_VERT = 8; // pos(3) + uv(2) + texLayer(1) + skyLight(1) + blockLight(1) - matches cubePropShader.vert static constexpr int VERTS_PER_ITEM = 36; // matches buildCube / padded sprite static constexpr int FLOATS_PER_ITEM = VERTS_PER_ITEM * FLOATS_PER_VERT; static constexpr int MAX_ITEMS = 64; // plenty for visible players @@ -53,7 +53,7 @@ class HeldItemRenderer { // One batched draw for every visible LivingEntity holding something. // `localPlayer` is processed alongside `entities` so the local player's - // hand renders in third-person โ€” it's tracked by livingEntitiesManager + // hand renders in third-person - it's tracked by livingEntitiesManager // but not present in `renderer->livingEntities`. Pass nullptr to skip. // Skips entities with DoDraw()==false (first-person mode hides the // local mesh, so the viewmodel takes over via drawFirstPerson) and any @@ -66,7 +66,7 @@ class HeldItemRenderer { // Viewmodel for the local player. Skips when nothing is held // (heldItemType 0 / BEGIN / AIR). - // `localCharacter` lets the viewmodel animate during arm swings โ€” pass + // `localCharacter` lets the viewmodel animate during arm swings - pass // the same ClientPlayer used elsewhere; nullptr keeps the cube static. void drawFirstPerson(const glm::mat4& projection, const glm::mat4& view, uint16_t heldItemType, diff --git a/include/client/Lighting.hpp b/include/client/Lighting.hpp index 9fa081fd..984af1c0 100644 --- a/include/client/Lighting.hpp +++ b/include/client/Lighting.hpp @@ -109,7 +109,7 @@ class Lighting { glm::vec3 color{1.0f, 0.8f, 0.5f}; bool omni = false; }; - // Max simultaneous spot lights โ€” must match MAX_SPOT_LIGHTS in lighting.frag + // Max simultaneous spot lights - must match MAX_SPOT_LIGHTS in lighting.frag // and ENTITY_MAX_SPOT_LIGHTS in entity_lighting.glsl. static constexpr int MAX_SPOT_LIGHTS = 16; // Upload the active flashlight set into spotLights[0..n-1] + numSpotLights. diff --git a/include/client/PackedVertex.hpp b/include/client/PackedVertex.hpp index 49dca477..6a93f4f7 100644 --- a/include/client/PackedVertex.hpp +++ b/include/client/PackedVertex.hpp @@ -8,7 +8,7 @@ // Used by ChunkRenderer for both solid terrain and water meshes. Decoded in // the vertex shaders via shaders/terrain_vertex_decode.glsl. // -// Bit layout โ€” chosen so positions can be stored at 1/16-block resolution to +// Bit layout - chosen so positions can be stored at 1/16-block resolution to // faithfully represent sub-block geometry (cactus side-inset, etc.). // // v0: posX:9 | posY:13 | posZ:9 | reserved:1 @@ -17,13 +17,13 @@ // // v1: normal:3 | corner:2 | texLayer:10 | skyLight:4 | waterAbove:1 | // blockLight:4 (bits 20-23) | reserved:8 -// normal โ€” face direction index 0..5 (matches mesher's `face` param, +// normal - face direction index 0..5 (matches mesher's `face` param, // indexes into NORMALS[6] in the GLSL include) -// corner โ€” quad corner index 0..3 (UVs reconstructed in the shader) -// texLayer โ€” texture array layer (10 bits = 1024 layers) -// skyLight โ€” quantized sky-light level 0..15 (matches the engine's +// corner - quad corner index 0..3 (UVs reconstructed in the shader) +// texLayer - texture array layer (10 bits = 1024 layers) +// skyLight - quantized sky-light level 0..15 (matches the engine's // internal 4-bit value; lossless) -// waterAbove โ€” 1 iff this face's block has a water block directly +// waterAbove - 1 iff this face's block has a water block directly // above it. Only meaningful for top faces; consumed by // the fragment shader to gate caustics so they don't // appear on dry cave floors that just happen to sit diff --git a/include/client/Renderer.hpp b/include/client/Renderer.hpp index 77496840..e7c483ff 100644 --- a/include/client/Renderer.hpp +++ b/include/client/Renderer.hpp @@ -45,12 +45,12 @@ class Renderer final : public CommonWorld { std::unordered_set chunksToBuild; // chunk to build and upload mesh // When each chunk's last fragment arrived. Used to give newly-received // chunks a grace period before organizeChunks is allowed to evict them - // by distance โ€” otherwise a stale player position right after a teleport + // by distance - otherwise a stale player position right after a teleport // or respawn can erase chunks that JUST arrived, and the server (which // already marked them sent in PlayerKnownChunks) never re-sends them. std::unordered_map chunkReceiveTime; std::vector> renderedChunks; - // Cached visibility list from the most recent terrain pass โ€” reused by + // Cached visibility list from the most recent terrain pass - reused by // renderVegetationOnly so we don't re-run frustum culling. Mutable because // render() is const-qualified. mutable std::vector> m_lastVisibleChunks; @@ -70,7 +70,7 @@ class Renderer final : public CommonWorld { // Water-pass helpers. Both render entry points iterate the same chunk // list with the same cull/uniform logic, differing only in which VAO - // they bind and which vertex count they draw โ€” factored out so the two + // they bind and which vertex count they draw - factored out so the two // flavors (ocean / placed) share the loop body. bool waterChunkCulled(const ChunkRenderer& chunk) const; template @@ -115,7 +115,7 @@ class Renderer final : public CommonWorld { float getVegetationMaxDistance() const { return vegetationMaxDistance; } void setVegetationMaxDistance(float d) { vegetationMaxDistance = d; } - // Wind sway shader cost โ€” uniform-controlled branch in vegetation.vert. + // Wind sway shader cost - uniform-controlled branch in vegetation.vert. // 0 = none (skip all sin/cos sway math), 1 = low (1 sin), 2 = high (current 3-5 sin) int getVegetationSwayQuality() const { return vegetationSwayQuality; } void setVegetationSwayQuality(int q) { vegetationSwayQuality = (q < 0 ? 0 : (q > 2 ? 2 : q)); } @@ -146,7 +146,7 @@ class Renderer final : public CommonWorld { /// Render only the terrain chunk loop (no vegetation). Populates the /// internal visibility cache so a subsequent `renderVegetationOnly` - /// call can reuse the same chunk list โ€” used by the Z-prepass path, + /// call can reuse the same chunk list - used by the Z-prepass path, /// where terrain runs twice (prepass + color) and vegetation once. void renderTerrainOnly(const std::shared_ptr& shaderProgram, const glm::mat4& view, @@ -170,7 +170,7 @@ class Renderer final : public CommonWorld { /// Returns true if any *ocean* (planar) water is visible in the /// current frustum. Used to gate the planar reflection/refraction - /// passes โ€” placed-bucket water doesn't need them. + /// passes - placed-bucket water doesn't need them. bool hasVisibleWater() const; /// Returns true if any *placed* water (sky-reflection bucket) is /// visible in the current frustum. diff --git a/include/client/SSAO.hpp b/include/client/SSAO.hpp index b59b7627..4a1ce72f 100644 --- a/include/client/SSAO.hpp +++ b/include/client/SSAO.hpp @@ -64,10 +64,10 @@ class SSAO { int SCR_WIDTH; int SCR_HEIGHT; bool enabled = true; - bool halfResolution = true; // Half-res SSAO for ~4x perf gain + bool halfResolution = false; // Half-res SSAO for ~4x perf gain bool resolutionChanged = false; - // Dirty flags โ€” avoid re-uploading uniforms every frame + // Dirty flags - avoid re-uploading uniforms every frame bool kernelDirty = true; glm::mat4 cachedProjection{0.0f}; // Zero-init so first comparison always triggers upload diff --git a/include/client/WaterRenderer.hpp b/include/client/WaterRenderer.hpp index 1ce71e79..85d4e44a 100644 --- a/include/client/WaterRenderer.hpp +++ b/include/client/WaterRenderer.hpp @@ -58,7 +58,7 @@ class WaterRenderer { float dudvTiling = 0.03f; // โ”€โ”€ Runtime graphics-quality settings โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - // Toggling these is free at steady state โ€” they're either uniform/CPU + // Toggling these is free at steady state - they're either uniform/CPU // checks or one-shot FBO rebuilds (refraction scale). bool isReflectionEnabled() const { return reflectionEnabled; } void setReflectionEnabled(bool enabled) { reflectionEnabled = enabled; } diff --git a/include/client/characters/ClientCreeper.hpp b/include/client/characters/ClientCreeper.hpp index b2bb69c8..4e07cc69 100644 --- a/include/client/characters/ClientCreeper.hpp +++ b/include/client/characters/ClientCreeper.hpp @@ -22,7 +22,7 @@ class ClientCreeper : public Creeper, public IClientEntity // fuse animation keeps advancing while the creeper stands still. void tickFuseAnimation(float deltaTime); - // Visible primed (fused) state โ€” client toggles from packet flag, draw pulses the body. + // Visible primed (fused) state - client toggles from packet flag, draw pulses the body. bool clientPrimed = false; // Smoothed 0..1 inflation; drives torso/head scale and wobble. diff --git a/include/client/characters/IClientEntity.hpp b/include/client/characters/IClientEntity.hpp index 37a621c9..8a607528 100644 --- a/include/client/characters/IClientEntity.hpp +++ b/include/client/characters/IClientEntity.hpp @@ -19,7 +19,7 @@ class IClientEntity : public virtual LivingEntity, public virtual Character { bool hasRenderPos = false; // Name of the skin PNG to bind when rendering this entity. Empty string - // means "no skin โ€” fall back to per-limb colors" + // means "no skin - fall back to per-limb colors" // Resolved against SkinManager at draw time. virtual std::string skinName() const { return ""; } }; diff --git a/include/client/characters/LivingEntitiesManager.hpp b/include/client/characters/LivingEntitiesManager.hpp index 56033820..e533a618 100644 --- a/include/client/characters/LivingEntitiesManager.hpp +++ b/include/client/characters/LivingEntitiesManager.hpp @@ -32,7 +32,7 @@ class LivingEntitiesManager const ICommonWorld* world); // Exposed so App.cpp can call lighting->uploadLightingUniforms/uploadCSMUniforms - // on the entity shader before draw() โ€” entity_lighting.glsl uses the same + // on the entity shader before draw() - entity_lighting.glsl uses the same // uniform names as lighting.frag so nothing else has to change. Shader& getShader() { return characterShader; } diff --git a/include/client/items/ItemPropEntityManager.hpp b/include/client/items/ItemPropEntityManager.hpp index ff46777f..e5537d8e 100644 --- a/include/client/items/ItemPropEntityManager.hpp +++ b/include/client/items/ItemPropEntityManager.hpp @@ -30,7 +30,7 @@ class ItemPropEntityManager { // Repack the per-entity vertex slots into the GPU buffer, skipping entities // whose DoDraw() returns false. Returns the number of slots actually - // written โ€” draw() uses this so glDrawArrays issues vertices only for + // written - draw() uses this so glDrawArrays issues vertices only for // rendered items instead of dragging the whole vector through the GPU. // `world` is used to sample chunk sky-light at each item's position so // items darken in caves like terrain does; may be null (defaults to 1.0). diff --git a/include/client/ui/TerrainDebugWindow.hpp b/include/client/ui/TerrainDebugWindow.hpp index d4417294..4e5afcf0 100644 --- a/include/client/ui/TerrainDebugWindow.hpp +++ b/include/client/ui/TerrainDebugWindow.hpp @@ -30,7 +30,7 @@ class TerrainDebugWindow { void reseedNoise(int32_t seed); void resizeTexture(int newSize); - // Terrain sampling helpers โ€” mirrors ChunkGeneration private methods exactly + // Terrain sampling helpers - mirrors ChunkGeneration private methods exactly float sampleContinentalness(const TerrainGenerationParams& p, float wx, float wz); float sampleErosion(const TerrainGenerationParams& p, float wx, float wz); float samplePV(const TerrainGenerationParams& p, float wx, float wz); diff --git a/include/server/Server.hpp b/include/server/Server.hpp index 0dacff0a..f6c8e730 100644 --- a/include/server/Server.hpp +++ b/include/server/Server.hpp @@ -103,7 +103,7 @@ class Server { void sendEntitiesPositionDeltas(); // One-shot snapshot of every existing living entity, sent to a freshly // connected client so stationary players/mobs (and their held items) are - // visible immediately โ€” the delta broadcast above only fires on entities + // visible immediately - the delta broadcast above only fires on entities // that are actively moving/swinging this tick. void sendEntitiesSnapshotTo(const sockaddr_in &cliaddr); diff --git a/include/shared/Chunk.hpp b/include/shared/Chunk.hpp index 22012027..c386bff9 100644 --- a/include/shared/Chunk.hpp +++ b/include/shared/Chunk.hpp @@ -39,7 +39,7 @@ struct std::hash { std::size_t h2 = std::hash()(p.second); // original formula produced collisions in a very predictable pattern. see boost::hash_combine // 2654435761u large odd number - 0x9e3779b9u = 2^32 / ฯ† so input 0 doesn't output 0 - // (h1 << 6) + (h1 >> 2) โ€” this mixes h1 with itself at two different bit positions, so the output depends on h1 in a non-trivial way. + // (h1 << 6) + (h1 >> 2) - this mixes h1 with itself at two different bit positions, so the output depends on h1 in a non-trivial way. return h1 ^ (h2 * 2654435761u + 0x9e3779b9u + (h1 << 6) + (h1 >> 2)); } }; diff --git a/include/shared/CommonWorld.inl b/include/shared/CommonWorld.inl index 928608d9..ad052f10 100644 --- a/include/shared/CommonWorld.inl +++ b/include/shared/CommonWorld.inl @@ -231,7 +231,7 @@ TargetType CommonWorld::getTarget(const LivingEntity& src, glm::ivec3& h template bool CommonWorld::isUnderwater(const glm::dvec3 &position) const { - // Floor in double space โ€” at large world coords (~1e6) float can't + // Floor in double space - at large world coords (~1e6) float can't // represent 1-block increments, which mis-floors near block boundaries. glm::ivec3 blockPos = glm::ivec3(glm::floor(position)); diff --git a/include/shared/Entity.hpp b/include/shared/Entity.hpp index 43288d96..81ef35b1 100644 --- a/include/shared/Entity.hpp +++ b/include/shared/Entity.hpp @@ -33,7 +33,7 @@ using entityID = uint32_t; // AABB stored in double so that block-collision math (floor(min.x + EPS) ...) // stays correct at very large world coordinates. With float, at 5M coords the // LSB is ~0.5m and adding entityWidth*0.5 to a player's position rounds to a -// different block boundary on +X vs -X โ€” manifesting as the player visually +// different block boundary on +X vs -X - manifesting as the player visually // clipping into blocks asymmetrically. struct AABB { glm::dvec3 min; @@ -148,7 +148,7 @@ class Entity { void applyImpulse(const glm::vec3& impulse) { velocity += impulse; } inline virtual EEntityTypes getEntityType() const = 0; virtual void calculateNewPosition(const ICommonWorld &world); - // Legacy getter โ€” returns float-precision snapshot of the position. + // Legacy getter - returns float-precision snapshot of the position. // Use getPositionD() when you need the precision (camera path, etc). inline const glm::vec3 getPosition() const { return glm::vec3(position); } inline const glm::dvec3 getPositionD() const { return position; } diff --git a/include/shared/Network.hpp b/include/shared/Network.hpp index 5f5816fe..3cb014c7 100644 --- a/include/shared/Network.hpp +++ b/include/shared/Network.hpp @@ -391,7 +391,7 @@ inline ReliabilityIngest reliabilityIngest( } // seq > expected: hole detected. Drop packets wildly past the window so a // peer can't waste a slot with a giant seq, then evict from the tail if - // the buffer would overflow โ€” packets near expectedSeq are what unblocks + // the buffer would overflow - packets near expectedSeq are what unblocks // the stream, so we keep those and shed the furthest-ahead ones. if (seq - r.expectedSeq > ReliabilityReceiver::kMaxReorderWindow) { return out; diff --git a/include/shared/Protocol.hpp b/include/shared/Protocol.hpp index 859e1e53..942854a5 100644 --- a/include/shared/Protocol.hpp +++ b/include/shared/Protocol.hpp @@ -185,7 +185,7 @@ struct NetPlayerMove final : public Packet { // Player position is sent in double precision so that, far from world // origin, the wire value doesn't snap to the f32 grid (~0.06 units at - // x=1e6) โ€” which would re-introduce visible jitter every server tick. + // x=1e6) - which would re-introduce visible jitter every server tick. double positionX; double positionY; double positionZ; @@ -281,7 +281,7 @@ struct NetEntityMove final : public Packet { uint16_t type = 0; // stone/dirt/etc.. for block - zombie/creeper/etc... for living entity. -1 to erase the entity // Position is sent in double precision. At ~5M blocks from origin, f32 ULP is - // ~0.5 blocks โ€” diagonal walking quantizes onto a coarser grid for X vs Z and + // ~0.5 blocks - diagonal walking quantizes onto a coarser grid for X vs Z and // produces visible zig-zag on the receiving client (sender's own position is // fine because it predicts locally). dvec3 keeps sub-block precision past 1e8. double positionX; diff --git a/shaders/characterCube.frag b/shaders/characterCube.frag index 1b159dd4..43f87e7d 100644 --- a/shaders/characterCube.frag +++ b/shaders/characterCube.frag @@ -1,13 +1,13 @@ #version 460 core uniform vec3 uColor; // fallback color when no skin is bound -uniform sampler2D uSkin; // 2D skin texture. V=0 is top of image; no V-flip applied โ€” UVs are already in skin-auth space. +uniform sampler2D uSkin; // 2D skin texture. V=0 is top of image; no V-flip applied - UVs are already in skin-auth space. uniform bool uUseTexture; // when true, sample uSkin; otherwise emit uColor // Sky-light at the entity's body-center, sampled host-side from the chunk // sky-light grid and uploaded per entity. 0 = pitch-black cave, 1 = open sky. // Mirrors fs_in.SkyLight in lighting.frag so mobs/players darken in caves the -// way terrain does โ€” without it, CSM-only shadowing leaves them bright +// way terrain does - without it, CSM-only shadowing leaves them bright // underground because the cascade frustum reaches in from above unobstructed. uniform float uEntitySkyLight; // Baked torch block-light at the entity's body-center (0..1). Added as a diff --git a/shaders/characterCube.vert b/shaders/characterCube.vert index 02a55c15..ab5a54f3 100644 --- a/shaders/characterCube.vert +++ b/shaders/characterCube.vert @@ -16,16 +16,16 @@ out vec2 vTex; out vec3 vFragPosRel; out vec3 vNormal; -// Matches the character cube face indexing in src/client/characters/cube.cpp โ€” +// Matches the character cube face indexing in src/client/characters/cube.cpp - // NOT the block face order in blockRenderingHelperFunctions.hpp. Character rig // axes: +X = character front (face), +Y = up, +Z = character left. const vec3 FACE_NORMALS[6] = vec3[6]( - vec3( 1.0, 0.0, 0.0), // 0: +X โ€” character front (face) - vec3(-1.0, 0.0, 0.0), // 1: -X โ€” character back - vec3( 0.0, 1.0, 0.0), // 2: +Y โ€” top - vec3( 0.0,-1.0, 0.0), // 3: -Y โ€” bottom - vec3( 0.0, 0.0, -1.0), // 4: -Z โ€” character right - vec3( 0.0, 0.0, 1.0) // 5: +Z โ€” character left + vec3( 1.0, 0.0, 0.0), // 0: +X - character front (face) + vec3(-1.0, 0.0, 0.0), // 1: -X - character back + vec3( 0.0, 1.0, 0.0), // 2: +Y - top + vec3( 0.0,-1.0, 0.0), // 3: -Y - bottom + vec3( 0.0, 0.0, -1.0), // 4: -Z - character right + vec3( 0.0, 0.0, 1.0) // 5: +Z - character left ); void main() diff --git a/shaders/clouds_composite.frag b/shaders/clouds_composite.frag index 90ac8af2..bc6cdd4b 100644 --- a/shaders/clouds_composite.frag +++ b/shaders/clouds_composite.frag @@ -3,7 +3,7 @@ // Post-terrain cloud composite + (in HDR mode) final tonemap. // // Reads the resolved (non-MSAA) scene color/depth and the low-res cloud RGBA texture, -// and composites clouds over the scene per-pixel using actual scene depth โ€” no +// and composites clouds over the scene per-pixel using actual scene depth - no // gl_FragDepth hacks. // // Two paths: @@ -36,7 +36,7 @@ uniform bool hdrMode; // true = blend in HDR + final tonemap here // compresses midtone saturation. uniform float saturation; -// ACES filmic tone mapping โ€” Krzysztof Narkowicz's cheap fit (2015). +// ACES filmic tone mapping - Krzysztof Narkowicz's cheap fit (2015). // Returns gamma-encoded (display-space) values: the ACES curve is applied to // linear input, then pow(1/2.2) encodes to display space (we don't use // GL_FRAMEBUFFER_SRGB, so gamma is done by hand). @@ -91,11 +91,11 @@ void main() { vec3 entry = cameraPosWorld + t * r; vec4 clip = projection * view * vec4(entry, 1.0); float cloudDepth = clamp(clip.z / clip.w * 0.5 + 0.5, 0.0, 1.0); - // sceneZ == 1.0 means the pixel is sky (no terrain) โ€” always composite. + // sceneZ == 1.0 means the pixel is sky (no terrain) - always composite. composite = (cloudDepth <= sceneZ); } } - // Inside the cloud layer: always composite (skip the depth-plane check โ€” + // Inside the cloud layer: always composite (skip the depth-plane check - // it would snap to the near plane and cause blinking when the camera // crosses the slab boundary at speed). diff --git a/shaders/cubePropShader.frag b/shaders/cubePropShader.frag index ce0a5673..7dbe9997 100644 --- a/shaders/cubePropShader.frag +++ b/shaders/cubePropShader.frag @@ -29,7 +29,7 @@ void main() // vSkyLight > 2.5 is the self-lit torch sentinel (the torch item itself // glows). Otherwise it's a normal 0..1 skylight and vBlockLight carries // baked torch light independently (added as a warm sky/shadow-independent - // term inside entityLitColor โ€” same as terrain/mobs). + // term inside entityLitColor - same as terrain/mobs). if (vSkyLight > 2.5) { FragColor = vec4(tex.rgb, 1.0); return; diff --git a/shaders/cubePropShader.vert b/shaders/cubePropShader.vert index e252b198..05be6f3d 100644 --- a/shaders/cubePropShader.vert +++ b/shaders/cubePropShader.vert @@ -22,7 +22,7 @@ flat out float vBlockLight; // Translation-free view (camera at origin of render space). aPos is already // camera-relative, so we never want the full view (its translation would // double-subtract). Matches the name lighting.vert uses, which is also what -// Lighting::uploadCSMUniforms sets โ€” no collision. +// Lighting::uploadCSMUniforms sets - no collision. uniform mat4 viewRot; uniform mat4 projection; diff --git a/shaders/entity_lighting.glsl b/shaders/entity_lighting.glsl index 35d79c70..0e62c789 100644 --- a/shaders/entity_lighting.glsl +++ b/shaders/entity_lighting.glsl @@ -6,7 +6,7 @@ // Differences from the terrain pipeline: // - No specular (entities have no spec maps). // - No SSAO (entities are too small for screen-space AO to add anything). -// - 3-tap PCF instead of up to 5x5 โ€” entity shadow edges don't need it. +// - 3-tap PCF instead of up to 5x5 - entity shadow edges don't need it. #define ENTITY_NR_POINT_LIGHTS 3 #define ENTITY_MAX_CASCADES 5 @@ -87,7 +87,7 @@ float entityCSMShadow(vec3 fragPosRel, vec3 normal, vec3 lightDir) { return 0.0; float biasedZ = pc.z - bias; - // 3-tap PCF โ€” cheap, sufficient for entity-scale geometry. + // 3-tap PCF - cheap, sufficient for entity-scale geometry. float lit = 0.0; lit += texture(shadowMapArray, vec4(pc.xy, layer, biasedZ)); lit += texture(shadowMapArray, vec4(pc.xy + texelSize, layer, biasedZ)); @@ -111,7 +111,7 @@ vec3 entityPointLightsContrib(vec3 fragPosRel, vec3 normal) { return sum; } -// Spot light (single slot) โ€” Lambertian with attenuation + cone falloff. +// Spot light (single slot) - Lambertian with attenuation + cone falloff. // Mirrors lighting.frag::CalcSpotLight minus specular. vec3 entitySpotLightContribOne(EL_SpotLight s, vec3 fragPosRel, vec3 normal) { vec3 toLight = s.position - fragPosRel; @@ -138,7 +138,7 @@ vec3 entitySpotLightContrib(vec3 fragPosRel, vec3 normal) { } // Final lit color. Mirrors lighting.frag's CalcDirLight (without specular): -// ambient *= (1 - shadow*0.5) [shadowed-ambient floor โ€” see lighting.frag:443] +// ambient *= (1 - shadow*0.5) [shadowed-ambient floor - see lighting.frag:443] // diffuse *= (1 - shadow) // Then applies sky-light modulation so caves // darken entities the same way they darken terrain. diff --git a/shaders/gui.vert b/shaders/gui.vert index 57832829..a3d2d92c 100644 --- a/shaders/gui.vert +++ b/shaders/gui.vert @@ -11,7 +11,7 @@ void main(void) { gl_Position = transformationMatrix * vec4(position, 0.0, 1.0); float ty = (position.y + 1.0) / 2.0; if (flipY) - textureCoords = vec2((position.x + 1.0) / 2.0, ty); // no flip โ€” correct for FBOs + textureCoords = vec2((position.x + 1.0) / 2.0, ty); // no flip - correct for FBOs else - textureCoords = vec2((position.x + 1.0) / 2.0, 1.0 - ty); // flip โ€” correct for loaded textures + textureCoords = vec2((position.x + 1.0) / 2.0, 1.0 - ty); // flip - correct for loaded textures } \ No newline at end of file diff --git a/shaders/lighting.frag b/shaders/lighting.frag index 2851c03a..3dfe3788 100644 --- a/shaders/lighting.frag +++ b/shaders/lighting.frag @@ -158,7 +158,7 @@ void main() // Sample the texture array using (u, v, layer) vec4 texColor = texture(blockTextures, vec3(fs_in.TexCoord, fs_in.TexLayer)); - // Alpha test (cutout discard) โ€” toggleable. In "Fast" leaf mode the host + // Alpha test (cutout discard) - toggleable. In "Fast" leaf mode the host // sets useAlphaTest=false so leaf cubes render fully opaque (no cutouts) // and the GPU keeps early-Z fully effective. if (useAlphaTest && texColor.a < 0.1) @@ -178,7 +178,7 @@ void main() // SSAO float AmbientOcclusion = 1.0; if (ssaoEnabled == 1) { - // Use full viewport size, not texture size โ€” the SSAO texture may + // Use full viewport size, not texture size - the SSAO texture may // be half-resolution (when blur is disabled + halfRes is on). vec2 ssaoUV = gl_FragCoord.xy / screenSize; AmbientOcclusion = texture(ssaoTexture, ssaoUV).r; @@ -196,11 +196,11 @@ void main() for(int i = 0; i < NR_POINT_LIGHTS; i++) result += CalcPointLight(pointLights[i], norm, fs_in.FragPosRel, viewDir, AmbientOcclusion, color); // phase 3: spot lights (local flashlight + any remote players whose - // flashlights are on this frame โ€” host caps at MAX_SPOT_LIGHTS). + // flashlights are on this frame - host caps at MAX_SPOT_LIGHTS). for (int i = 0; i < numSpotLights; ++i) result += CalcSpotLight(spotLights[i], norm, fs_in.FragPosRel, viewDir, AmbientOcclusion, color); - // Caustics โ€” only on faces that are *actually* under a water block. + // Caustics - only on faces that are *actually* under a water block. // The WaterAbove flag is baked at mesh time (top faces whose +Y // neighbour is water). This is stricter than "below sea level" (which // lit cave floors) and stricter than SkyLight (which leaks sideways @@ -257,7 +257,7 @@ void main() { vec3 cascadeColor; if (debugCascadeLayer == 0) - cascadeColor = vec3(1.0, 0.0, 0.0); // Red โ€” closest + cascadeColor = vec3(1.0, 0.0, 0.0); // Red - closest else if (debugCascadeLayer == 1) cascadeColor = vec3(0.0, 1.0, 0.0); // Green else if (debugCascadeLayer == 2) @@ -265,7 +265,7 @@ void main() else if (debugCascadeLayer == 3) cascadeColor = vec3(1.0, 1.0, 0.0); // Yellow else - cascadeColor = vec3(1.0, 0.0, 1.0); // Magenta โ€” farthest + cascadeColor = vec3(1.0, 0.0, 1.0); // Magenta - farthest // Mix: 80% original color + 20% cascade tint FragColor = vec4(mix(FragColor.rgb, cascadeColor, 0.2), FragColor.a); @@ -333,7 +333,7 @@ float CSMShadowCalculation(vec3 fragPosRel) projCoords.y < 0.0 || projCoords.y > 1.0) return 0.0; - // 5. Bias โ€” scale proportional to the texel size of this cascade. + // 5. Bias - scale proportional to the texel size of this cascade. // Larger cascades cover more world space per texel, so they // need proportionally more bias. We derive the scale from the // shadow map resolution vs the cascade's projected extent (which @@ -483,7 +483,7 @@ vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir, float ao, vec3 texC // Diffuse & specular: also scaled by skyFactor. // Without this, caves lit by the sun at an angle (no terrain // between sun and cave interior from the CSM's perspective) - // would still receive full diffuse/specular โ€” looking bright + // would still receive full diffuse/specular - looking bright // underground. skyFactor tells us the block is enclosed, so // direct sunlight shouldn't reach it regardless of the shadow // map's opinion. diff --git a/shaders/lighting.vert b/shaders/lighting.vert index 2684cac1..59aafb4d 100644 --- a/shaders/lighting.vert +++ b/shaders/lighting.vert @@ -25,7 +25,7 @@ uniform mat4 viewRot; uniform vec3 chunkRel; // Per-chunk: chunkOrigin in world space (float). Used only to reconstruct // world-space FragPos for lighting / shadows / fog. Suffers the same -// precision quantization at huge distances as before โ€” but the *geometry* +// precision quantization at huge distances as before - but the *geometry* // (gl_Position) is computed from the precise camera-relative path. uniform vec3 chunkOriginWorld; diff --git a/shaders/luminance_reduce.frag b/shaders/luminance_reduce.frag index 8f4e27f5..3560090e 100644 --- a/shaders/luminance_reduce.frag +++ b/shaders/luminance_reduce.frag @@ -5,7 +5,7 @@ // each frame to drive auto-exposure adaptation. // // We do a 3x3 jittered tap pattern to absorb noise from bright pixels (sun, -// specular highlights). The cost is trivial โ€” 9 samples * 64 * 64 fragments. +// specular highlights). The cost is trivial - 9 samples * 64 * 64 fragments. in vec2 vUV; out float FragColor; diff --git a/shaders/sky.frag b/shaders/sky.frag index 412a4f39..cfa4537d 100644 --- a/shaders/sky.frag +++ b/shaders/sky.frag @@ -26,7 +26,7 @@ uniform vec3 cameraPosWorld; uniform float seaLevel; uniform float exposure; // exposure for simple tone mapping (1 - exp(-exposure * color)) // When false, the scene framebuffer is HDR (RGBA16F) and the final tonemap is -// performed once in clouds_composite. We must NOT tonemap here in that case โ€” +// performed once in clouds_composite. We must NOT tonemap here in that case - // emit linear radiance instead. Defaults to true for the LDR path. uniform bool tonemapHere; uniform float atmDensity; // 1.0 = Earth-like, lower -> closer to space diff --git a/shaders/skyLUT.frag b/shaders/skyLUT.frag index a49cb181..cc1ea974 100644 --- a/shaders/skyLUT.frag +++ b/shaders/skyLUT.frag @@ -96,7 +96,7 @@ void main() { float farDist = t1o; // Integration - const int SAMPLES = 16; // More samples than runtime โ€” this is precomputed + const int SAMPLES = 16; // More samples than runtime - this is precomputed const int SAMPLES_SUN = 8; float segment = farDist / float(SAMPLES); diff --git a/shaders/terrain_depth_prepass.frag b/shaders/terrain_depth_prepass.frag index a513f878..8463c275 100644 --- a/shaders/terrain_depth_prepass.frag +++ b/shaders/terrain_depth_prepass.frag @@ -1,7 +1,7 @@ #version 460 core // Z-prepass fragment shader. When useAlphaTest is true, discards transparent // texels (leaf cutouts) so the depth buffer matches what the color pass will -// produce โ€” without this, GL_EQUAL would fail on transparent edges and leaves +// produce - without this, GL_EQUAL would fail on transparent edges and leaves // would vanish. In Fast leaf mode the host sets useAlphaTest=false, the // fragment shader becomes a no-op, and early-Z is fully unleashed. in vec2 TexCoord; diff --git a/shaders/terrain_depth_prepass.vert b/shaders/terrain_depth_prepass.vert index d16a4576..d50be1c7 100644 --- a/shaders/terrain_depth_prepass.vert +++ b/shaders/terrain_depth_prepass.vert @@ -2,7 +2,7 @@ #include "terrain_vertex_decode.glsl" // Z-prepass for terrain. Reads the same packed VAO as lighting.vert (location -// 0 = v0, location 1 = v1). Emits position + texture coords only โ€” just enough +// 0 = v0, location 1 = v1). Emits position + texture coords only - just enough // to alpha-test leaves so the depth buffer matches the color pass exactly // (required for glDepthFunc(GL_EQUAL) to work). layout (location = 0) in uint aV0; @@ -24,7 +24,7 @@ void main() { TexLayer = float(unpackTexLayer(aV1)); gl_Position = projection * viewRot * vec4(cameraRelPos, 1.0); - // Same clip plane as lighting.vert โ€” the prepass must clip identically + // Same clip plane as lighting.vert - the prepass must clip identically // to the color pass or GL_EQUAL fails along the water surface. gl_ClipDistance[0] = dot(vec4(chunkOriginWorld + aPos, 1.0), clipPlane); } diff --git a/shaders/terrain_vertex_decode.glsl b/shaders/terrain_vertex_decode.glsl index c26c44b8..e187fc3c 100644 --- a/shaders/terrain_vertex_decode.glsl +++ b/shaders/terrain_vertex_decode.glsl @@ -4,7 +4,7 @@ // // Bit layout (must match include/client/PackedVertex.hpp): // v0: posX:9 | posY:13 | posZ:9 | reserved:1 -// โ€” positions are 1/16-block fixed point (multiply by 1/16 to recover floats) +// - positions are 1/16-block fixed point (multiply by 1/16 to recover floats) // v1: normal:3 | corner:2 | texLayer:10 | skyLight:4 | waterAbove:1 | blockLight:4 | reserved:8 // Face direction lookup. Matches ChunkRenderer's `face` parameter ordering: @@ -29,7 +29,7 @@ const vec2 CORNERS[4] = vec2[4]( ); vec3 unpackPos(uint v0) { - // 1/16 block fixed point โ€” divide to recover float position. + // 1/16 block fixed point - divide to recover float position. return vec3( float( v0 & 0x1FFu), float((v0 >> 9) & 0x1FFFu), diff --git a/shaders/vegetation.frag b/shaders/vegetation.frag index d6837dbe..9da41172 100644 --- a/shaders/vegetation.frag +++ b/shaders/vegetation.frag @@ -75,7 +75,7 @@ void main() { // Sample texture from array (premultiplied alpha) vec4 texColor = texture(blockTextures, vec3(fs_in.TexCoord, fs_in.TexLayer)); - // Discard transparent pixels โ€” threshold raised to catch semi-transparent + // Discard transparent pixels - threshold raised to catch semi-transparent // mipmap edge pixels that would otherwise occlude terrain behind if (texColor.a < 0.5) discard; @@ -135,7 +135,7 @@ void main() { result += spotLights[i].diffuse * ndotl * att * intensity * texColor.rgb; } - // Apply underwater tint โ€” blue-green color absorption + // Apply underwater tint - blue-green color absorption if (fs_in.IsUnderwater > 0.5) { vec3 waterTint = vec3(0.4, 0.7, 0.6); result *= waterTint; diff --git a/shaders/vegetation.vert b/shaders/vegetation.vert index ce1ed131..6d1dd667 100644 --- a/shaders/vegetation.vert +++ b/shaders/vegetation.vert @@ -44,7 +44,7 @@ uniform int vegetationDensity; void main() { // โ”€โ”€ Density culling: cheapest path wins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Park skipped instances at clip-space (2,2,2,1) so they're trivially - // culled โ€” vertex still runs but exits before the expensive math below. + // culled - vertex still runs but exits before the expensive math below. if (vegetationDensity > 1 && (gl_InstanceID % vegetationDensity) != 0) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_ClipDistance[0] = -1.0; @@ -68,7 +68,7 @@ void main() { bool isUnderwater = (worldPos.y < seaLevel); // โ”€โ”€ Sway: skip entirely on quality 0 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - // Uniform branch โ€” coherent across all fragments, so the GPU only + // Uniform branch - coherent across all fragments, so the GPU only // executes the path that's selected; the others cost nothing. if (vegetationSwayQuality > 0) { // Distance-based LOD: fade sway out as we approach the cutoff. @@ -99,7 +99,7 @@ void main() { swayX = bend * s; swayZ = bend * 0.7 * s; // reuse the sin to avoid a second call } else { - // Full quality โ€” original 5-sin organic motion + // Full quality - original 5-sin organic motion swayX = bend * sin(time * 0.35 + worldPos.x * 0.4 + worldPos.z * 0.25 + plantPhase); swayZ = bend * sin(time * 0.28 + worldPos.x * 0.3 + worldPos.z * 0.5 + plantPhase + 1.57); swayX += bend * 0.3 * sin(time * 0.6 + worldPos.z * 0.7 + plantPhase * 0.5); @@ -115,7 +115,7 @@ void main() { swayX = aPos.y * 0.08 * s; swayZ = swayX * 0.3; // reuse the sin } else { - // Full quality โ€” original 3-sin land sway + // Full quality - original 3-sin land sway float sway = aPos.y * 0.08 * sin(time * 1.5 + worldPos.x * 0.8 + worldPos.z * 0.6 + plantPhase) + aPos.y * 0.03 diff --git a/shaders/water.frag b/shaders/water.frag index 57bffd16..ef43ec93 100644 --- a/shaders/water.frag +++ b/shaders/water.frag @@ -51,7 +51,7 @@ vec2 sampleDistortion(vec2 baseUV) { + (texture(dudvMap, c2).rg * 2.0 - 1.0) * 0.5); } -// Two-tap normal map sampling at different scales โ€” the small-scale layer +// Two-tap normal map sampling at different scales - the small-scale layer // adds high-frequency ripple detail without retiling the big waves. vec3 sampleNormal(vec2 distortedUV) { vec4 n1 = texture(normalMap, distortedUV); @@ -76,7 +76,7 @@ void main() { // Multi-octave dudv distortion vec2 totalDistortion = sampleDistortion(textureCoords) * waveStrength * clamp(waterDepth/20.0, 0.0, 1.0); - // Refraction also bends through the rippled surface โ€” use a smaller + // Refraction also bends through the rippled surface - use a smaller // factor so the underwater silhouette stays readable while still // tracking the surface dudv, then clamp to keep the sample inside the // refraction FBO (otherwise we'd read the above-water clipped region). @@ -118,7 +118,7 @@ void main() { vec4 refractColor = texture(refractionTexture, refractTexCoords); refractColor = mix(refractColor, murkyWaterColor, clamp(waterDepth/60.0, 0.0, 1.0)); - // Multi-octave normal โ€” see sampleNormal(). + // Multi-octave normal - see sampleNormal(). // Use the *first* sampled UV (consistent with old single-tap behavior) for // the distortion that drives normals. vec2 distortedTexCoords = textureCoords + totalDistortion; @@ -150,7 +150,7 @@ void main() { // Distance-based color shift: real water turns sky-blue at distance. // Mix toward the sky color sampled in the view direction. This is on top - // of any fog blend below โ€” the two together give a smooth horizon. + // of any fog blend below - the two together give a smooth horizon. float viewDist = length(toCameraVector); { vec3 viewDirToFrag = normalize(-toCameraVector); diff --git a/shaders/water.vert b/shaders/water.vert index 3aed5963..4665e6bb 100644 --- a/shaders/water.vert +++ b/shaders/water.vert @@ -28,19 +28,19 @@ uniform vec2 waveAnchor; uniform float waveTime; // Sum of two Gerstner waves. Returns vertical displacement only (we don't -// circular-displace the xz, since the mesh is a 1ร—1 grid per quad โ€” pure y +// circular-displace the xz, since the mesh is a 1ร—1 grid per quad - pure y // displacement is enough to give silhouette wobble and parallax). // float gerstnerY(vec2 worldXZ) { - // Wave 1 โ€” broad, slow. + // Wave 1 - broad, slow. const vec2 dir1 = vec2( 0.7071, 0.7071); const float len1 = 16.0; const float amp1 = 0.05; // wave amplitude (max vertical displacement) const float k1 = 6.28318530718 / len1; float phase1 = k1 * dot(dir1, worldXZ) - waveTime * 1.5; - // Wave 2 โ€” small, fast, crossing direction. + // Wave 2 - small, fast, crossing direction. const vec2 dir2 = vec2(-0.5, 0.866); const float len2 = 7.0; const float amp2 = 0.024; // smaller amplitude for the second wave @@ -56,7 +56,7 @@ void main() { // Displace water-surface vertices. A vertex sits on the surface when // either: - // - its face normal is +Y (top face โ€” all four corners are surface verts), or + // - its face normal is +Y (top face - all four corners are surface verts), or // - it's a side face vertex on the upper edge of the block. // Mesher emits 6 verts per face with cornerIdx cycling 0,1,2,2,3,0; for // side faces, corners 2 and 3 are the upper edge (top-right / top-left diff --git a/shaders/water_placed.frag b/shaders/water_placed.frag index 8283df22..fe277c01 100644 --- a/shaders/water_placed.frag +++ b/shaders/water_placed.frag @@ -5,7 +5,7 @@ // reflection texture is mirrored across y == seaLevel and the refraction // texture is clipped at y == seaLevel, so neither of them is meaningful for // this geometry. Instead we read reflection from the sky LUT and treat the -// "underwater" term as a flat blue tint โ€” nothing here depends on the +// "underwater" term as a flat blue tint - nothing here depends on the // fragment's world Y, so it shades correctly at any height. in vec4 clipSpace; @@ -44,7 +44,7 @@ uniform vec3 underwaterFogColor; #include "sky_common.glsl" -// Two-octave dudv โ€” same idea as ocean shader. Each octave gets its own +// Two-octave dudv - same idea as ocean shader. Each octave gets its own // scroll (moveFactor / moveFactor2) so the GL_REPEAT wrap is integer-clean // and the two layers drift apart over time without snapping. vec2 sampleDistortion(vec2 baseUV) { @@ -114,7 +114,7 @@ void main() { vec3 viewIncoming = -viewVector; // Sky reflection. Perturb in the face's tangent plane (T, B) so the - // jitter is consistent across face orientations โ€” the old `reflectDir.xz` + // jitter is consistent across face orientations - the old `reflectDir.xz` // shake assumed a horizontal surface. vec3 reflectDir = reflect(viewIncoming, normal); reflectDir += (faceT * totalDistortion.x + faceB * totalDistortion.y); @@ -127,7 +127,7 @@ void main() { // Fresnel float refractiveFactor = clamp(dot(viewVector, normal), 0.001, 0.999); - // Soft + sharp specular stacked โ€” same pattern as ocean shader. + // Soft + sharp specular stacked - same pattern as ocean shader. vec3 reflectedLight = reflect(-sunDir, normal); float specSoft = pow(max(dot(reflectedLight, viewVector), 0.0), shineDamper); float specSharp = pow(max(dot(reflectedLight, viewVector), 0.0), 200.0); @@ -139,7 +139,7 @@ void main() { col = mix(col, waterColor, 0.2) + specularHighlights; FragColor = vec4(col, 0.75); - // Distance-based horizon mix โ€” even small ponds benefit a little when + // Distance-based horizon mix - even small ponds benefit a little when // looking across a long stretch of placed water. float viewDist = length(toCameraVector); { diff --git a/shaders/water_placed.vert b/shaders/water_placed.vert index b3871e70..53bc704b 100644 --- a/shaders/water_placed.vert +++ b/shaders/water_placed.vert @@ -26,7 +26,7 @@ uniform vec3 chunkRel; uniform vec2 texAnchor; // Vertical companion to texAnchor.xz, used by side-face UVs so the texture // stays world-space-stable when the eye moves up or down. Anchored to a -// multiple of the dudv repeat period on the CPU โ€” same trick as XZ. +// multiple of the dudv repeat period on the CPU - same trick as XZ. uniform float texAnchorY; uniform float tiling; @@ -71,7 +71,7 @@ void main() { gl_Position = clipSpace; // Per-face UV projection. Side faces project onto (horizontal axis, Y) - // so the dudv texture doesn't smear vertically โ€” using only XZ would + // so the dudv texture doesn't smear vertically - using only XZ would // give a constant UV across a side face's vertical extent, which is // exactly what made the sides look stretched. Y has no anchor (chunk // height is bounded, so it stays in f32 range) and feeds V directly. diff --git a/src/client/App.cpp b/src/client/App.cpp index 2bd55933..34312b3c 100644 --- a/src/client/App.cpp +++ b/src/client/App.cpp @@ -71,7 +71,7 @@ void App::init(const std::string& serverIp) { audio = std::make_unique(); // If SoLoud can't open a backend (headless / no audio device / driver mismatch), - // drop the manager rather than leave it half-initialised โ€” every playSfx*/update + // drop the manager rather than leave it half-initialised - every playSfx*/update // call later guards on `if (audio)`, so the game runs silent instead of crashing. if (!audio->init()) { std::cerr << "[Audio] disabled (init failed)" << std::endl; @@ -150,7 +150,7 @@ void App::init(const std::string& serverIp) { gBuffer = std::make_shared(screenWidth, screenHeight); ssao = std::make_shared(screenWidth, screenHeight); - // Scene FBO (MSAA) โ€” sample count must match the GLFW window hint above. + // Scene FBO (MSAA) - sample count must match the GLFW window hint above. // hdrEnabled selects between GL_RGBA16F (HDR) and GL_RGBA8 (LDR fallback). sceneFBO = std::make_unique(screenWidth, screenHeight, 8, hdrEnabled); @@ -679,7 +679,7 @@ void App::setUdpClientPacketCallback() } audio->onCreeperExploded(key, epos, listenerPos); } - // Hurt one-shot (server bit 0x10). Skip on the death packet (type == -1) โ€” the + // Hurt one-shot (server bit 0x10). Skip on the death packet (type == -1) - the // AudioManager's death-edge sweep handles that case with the proper death sfx. if (audio && p.eEntityType == EEntityTypes::LIVING_ENTITIES @@ -890,7 +890,7 @@ void App::loadResources() { gBufferShader->use(); gBufferShader->setInt("blockTextures", 0); - // Z-prepass shader โ€” minimal vertex transform + alpha-test discard. + // Z-prepass shader - minimal vertex transform + alpha-test discard. depthPrepassShader = std::make_shared( "shaders/terrain_depth_prepass.vert", "shaders/terrain_depth_prepass.frag"); depthPrepassShader->use(); @@ -1218,7 +1218,7 @@ void App::render() { if (waterMoveOffset2 > 1.0f) waterMoveOffset2 -= 1.0f; waterRenderer->setWaterMoveFactor(waterMoveOffset); waterRenderer->setWaterMoveFactor2(waterMoveOffset2); - // Non-wrapping wave phase โ€” drives Gerstner displacement in the + // Non-wrapping wave phase - drives Gerstner displacement in the // vertex shader. Independent of waterMoveOffset (which wraps for // dudv UV scrolling). waterRenderer->advanceWaveTime(deltaTime); @@ -1266,7 +1266,7 @@ void App::render() { if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - // render to screen โ€” pass useSSAO=false when GBuffer was skipped this frame + // render to screen - pass useSSAO=false when GBuffer was skipped this frame renderScene(view, projection, clipPlane); // Render water with proper shader setup @@ -1275,11 +1275,11 @@ void App::render() { if (waterVisible || placedWaterVisible) { const float chunkDist = renderer->getMaxRenderedChunkDist(); waterRenderer->setFogParams(fogEnabled, chunkDist * fogStartFraction, chunkDist, fogStrength); - // Ocean surface โ€” needs the planar reflection/refraction textures + // Ocean surface - needs the planar reflection/refraction textures // produced by the passes above; only run when there's any to draw. if (waterVisible) waterRenderer->renderWaterSurface(projection); - // Placed/spread water surface โ€” sky-reflection shader, independent + // Placed/spread water surface - sky-reflection shader, independent // of any global plane. Drawn after ocean so its own depth writes // sort against ocean fragments at the same Y. if (placedWaterVisible) @@ -1313,7 +1313,7 @@ void App::render() { lighting->setSkyExposure(manualExposure); } - // cameraEyeWorld must match the eye encoded in `view` โ€” the composite + // cameraEyeWorld must match the eye encoded in `view` - the composite // shader reconstructs the view ray via inverse(projection*view) and // computes (farWorld - cameraPosWorld). Mismatches also skew the // inside-layer check used to skip the depth-plane comparison. @@ -1328,7 +1328,7 @@ void App::render() { // First-person viewmodel for the local player's held item. Drawn into // the backbuffer (post clouds composite) so it always lands on top of // the world but underneath the HUD/menus that come below. Skipped in - // third-person โ€” drawForEntities already attached the item to the body. + // third-person - drawForEntities already attached the item to the body. if (m_heldItemRenderer && camera && !camera->isThirdPersonCameraActive()) { const uint16_t held = camera->getPlayer()->heldItemType; if (held != 0) { @@ -1595,7 +1595,7 @@ void App::renderScene(const glm::mat4 &view, const glm::mat4 &projection, const vegShader->setMat4("view", view); vegShader->setMat4("projection", projection); // Vegetation fragments now use FragPosRel (camera-relative) for fog distances, - // so viewPos is the origin of render space โ€” vec3(0). + // so viewPos is the origin of render space - vec3(0). vegShader->setVec3("viewPos", glm::vec3(0.0f)); // Use the same day/night cycle as the main lighting system @@ -1604,7 +1604,7 @@ void App::renderScene(const glm::mat4 &view, const glm::mat4 &projection, const float day = glm::clamp(sunElevation * 2.0f, 0.0f, 1.0f); day = glm::smoothstep(0.0f, 1.0f, day); - // Matches the value in Lighting::uploadLightingUniforms โ€” kept in sync + // Matches the value in Lighting::uploadLightingUniforms - kept in sync // so terrain and vegetation share the same night-time floor. constexpr float nightAmbientMin = 0.05f; glm::vec3 ambientColor = lighting->getDirectionalAmbientColor() * (nightAmbientMin + (1.0f - nightAmbientMin) * day); @@ -1654,7 +1654,7 @@ void App::renderScene(const glm::mat4 &view, const glm::mat4 &projection, const // โ”€โ”€ Z-prepass โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Render terrain depth-only with color writes off. Subsequent color // pass uses GL_EQUAL so each pixel only runs the heavy lighting - // shader once, regardless of overdraw โ€” big win in dense jungle. + // shader once, regardless of overdraw - big win in dense jungle. depthPrepassShader->use(); depthPrepassShader->setMat4("projection", projection); depthPrepassShader->setVec4("clipPlane", clipPlane); @@ -1769,7 +1769,7 @@ void App::renderScene(const glm::mat4 &view, const glm::mat4 &projection, const } // Keep the local player's heldItemType in sync with their inventory each - // frame โ€” no server packet reports our own held item back to us, and + // frame - no server packet reports our own held item back to us, and // HeldItemRenderer reads this field uniformly for every entity. if (localPlayer.inventory) { localPlayer.heldItemType = localPlayer.inventory->getActiveItemID(); @@ -1791,14 +1791,14 @@ void App::renderScene(const glm::mat4 &view, const glm::mat4 &projection, const // end of render() so it lands on top of the final composited frame. if (m_heldItemRenderer) { // cubePropShader.frag pulls dir/point/CSM uniforms the same way the - // dropped-item path does โ€” upload them here too so held items don't + // dropped-item path does - upload them here too so held items don't // render unlit. Shader& hShader = m_heldItemRenderer->getShader(); lighting->uploadLightingUniforms(hShader, camera->getEyePosD(), camera->getPlayer()->getCameraDir()); uploadActiveSpotLights(hShader); lighting->uploadCSMUniforms(hShader, view); - // Pass the local player explicitly โ€” it lives only in + // Pass the local player explicitly - it lives only in // livingEntitiesManager, not in renderer->livingEntities, so without // this branch the local hand never renders in third-person. LivingEntity* localForHand = @@ -1855,7 +1855,7 @@ void App::uploadActiveSpotLights(Shader& shader) const glm::vec3 posRel = glm::vec3(le->getPositionD() - eyePos); posRel.y += static_cast(le->getEntityHeight()) * 0.9f; - // Look direction from yaw/pitch โ€” mirrors PlayerMovement::updateCameraVectors. + // Look direction from yaw/pitch - mirrors PlayerMovement::updateCameraVectors. const float yr = glm::radians(le->yaw); const float pr = glm::radians(le->pitch); glm::vec3 dir = glm::normalize(glm::vec3( @@ -2221,7 +2221,7 @@ void App::debugWindow() { ImGui::SliderFloat("Hilt offset Y", t.hiltDY, -1.0f, 1.0f, "%.3f"); ImGui::SliderFloat("Hilt offset Z", t.hiltDZ, -1.0f, 1.0f, "%.3f"); if (ImGui::SliderFloat("Voxel depth", t.voxelDepth, 1.0f/64.0f, 0.5f, "%.4f")) { - // Depth is baked into the cached extrusion โ€” invalidate + // Depth is baked into the cached extrusion - invalidate // so it rebuilds next frame at the new thickness. if (m_heldItemRenderer) m_heldItemRenderer->clearWeaponMeshCache(); } @@ -2262,7 +2262,7 @@ void App::debugWindow() { } if (ImGui::BeginTabItem("Graphics Quality")) { - // Preset buttons โ€” apply shadow + water + vegetation + SSAO together. + // Preset buttons - apply shadow + water + vegetation + SSAO together. if (ImGui::Button("Performance")) { // Shadows lighting->setCascadeCount(2); @@ -2270,14 +2270,14 @@ void App::debugWindow() { lighting->setShadowFarPlane(250.0f); lighting->setPcfQuality(Lighting::PcfQuality::Low); lighting->setShadowAlphaTest(false); - // Water โ€” disable reflection, half-res refraction without vegetation + // Water - disable reflection, half-res refraction without vegetation waterRenderer->setReflectionEnabled(false); waterRenderer->setRefractionResolutionScale(0.5f, screenWidth, screenHeight); waterRenderer->setRefractionVegetationEnabled(false); waterRenderer->setReflectionMaxDistance(0.0f); // Vegetation distance limiter (jungle scenes) renderer->setVegetationMaxDistance(100.0f); - // Vegetation: no sway, half density โ€” biggest jungle win + // Vegetation: no sway, half density - biggest jungle win renderer->setVegetationSwayQuality(0); renderer->setVegetationSwayMaxDistance(0.0f); renderer->setVegetationDensity(2); @@ -2324,7 +2324,7 @@ void App::debugWindow() { renderer->setVegetationSwayMaxDistance(0.0f); renderer->setVegetationDensity(1); depthPrepassEnabled = true; - // High: original look โ€” leaves transparent, every face emitted. + // High: original look - leaves transparent, every face emitted. ChunkRenderer::sLeafRenderMode = ChunkRenderer::LeafRenderMode::Fancy; for (auto &cp : renderer->getRenderedChunks()) if (auto c = cp.lock()) c->buildMesh(); } @@ -2409,9 +2409,9 @@ void App::debugWindow() { chunk->buildMesh(); } ImGui::SetItemTooltip( - "Fast โ€” leaves render as solid green cubes. Mesher culls leaf-to-leaf and solid-to-leaf faces. Cheapest.\n" - "Fancy โ€” original look: leaves are alpha-tested, every face emitted (you can see leaves through other leaves). Most expensive.\n" - "Smart โ€” leaves keep alpha cutouts on outer faces, but mesher skips internal faces. Hollow canopies; recommended balance."); + "Fast - leaves render as solid green cubes. Mesher culls leaf-to-leaf and solid-to-leaf faces. Cheapest.\n" + "Fancy - original look: leaves are alpha-tested, every face emitted (you can see leaves through other leaves). Most expensive.\n" + "Smart - leaves keep alpha cutouts on outer faces, but mesher skips internal faces. Hollow canopies; recommended balance."); if (ImGui::Button("Rebuild all chunk meshes")) { for (auto &chunkPtr : renderer->getRenderedChunks()) @@ -2488,7 +2488,7 @@ void App::debugWindow() { sceneFBO->setHDR(hdrEnabled); lighting->setHDREnabled(hdrEnabled); // Water reflection/refraction targets must match the scene's - // color space โ€” otherwise HDR scene radiance gets clamped to + // color space - otherwise HDR scene radiance gets clamped to // [0,1] in those FBOs and water.frag then samples LDR values // back into the HDR scene buffer. if (waterRenderer) @@ -2499,7 +2499,7 @@ void App::debugWindow() { if (!hdrEnabled) lighting->setSkyExposure(manualExposure); } - // Saturation works in either HDR or LDR mode โ€” it's applied in + // Saturation works in either HDR or LDR mode - it's applied in // display space at the end of clouds_composite. Default 1.2 to // compensate for the tonemap's midtone desaturation when fed // sRGB-encoded textures (see clouds_composite.frag). @@ -2870,7 +2870,7 @@ void App::debugWindow() { // โ”€โ”€ Settings โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ if (ImGui::BeginTabItem("Settings")) { // Audio sliders are skipped entirely when init() failed and we nulled - // the manager โ€” the rest of the Settings tab is unrelated and still useful. + // the manager - the rest of the Settings tab is unrelated and still useful. if (audio) { float masterVolume = audio->getMasterVolume(); float musicVolume = audio->getMusicVolume(); @@ -3238,7 +3238,7 @@ bool App::popSubMenuOnEscape() { return true; } if (mgr == controlsMenu) { - // Don't pop while a key rebind is pending โ€” the rebinder consumes ESC. + // Don't pop while a key rebind is pending - the rebinder consumes ESC. if (!controlsMenu->getChangeRequested()) menuManager = settingsMenu; return true; diff --git a/src/client/AudioManager.cpp b/src/client/AudioManager.cpp index 33692d3e..2c9a6b8a 100644 --- a/src/client/AudioManager.cpp +++ b/src/client/AudioManager.cpp @@ -38,7 +38,7 @@ bool AudioManager::init() { SoLoud::result r = engine.init(); if (r != SoLoud::SO_NO_ERROR) { std::cerr << "[Audio] SoLoud init failed: " << r - << " โ€” continuing with no sound" << std::endl; + << " - continuing with no sound" << std::endl; // Last-resort: NOSOUND keeps the engine API usable so the rest of // the app doesn't have to special-case a null engine. r = engine.init(SoLoud::Soloud::CLIP_ROUNDOFF, SoLoud::Soloud::NOSOUND); @@ -49,7 +49,7 @@ bool AudioManager::init() { } // Inverse-distance attenuation matches what people expect from "3D audio". - engine.set3dSoundSpeed(343.0f); // speed of sound (m/s) โ€” affects doppler + engine.set3dSoundSpeed(343.0f); // speed of sound (m/s) - affects doppler // Route music & sfx through their own buses so volumes can be controlled independently. musicBusHandle = engine.play(musicBus); @@ -90,7 +90,7 @@ bool AudioManager::loadSfx(SoundId id, const std::vector& paths) { auto wav = std::make_unique(); SoLoud::result r = wav->load(p.c_str()); if (r != SoLoud::SO_NO_ERROR) { - // Missing assets are fine โ€” log once and move on. Game still runs silent for that id. + // Missing assets are fine - log once and move on. Game still runs silent for that id. std::cerr << "[Audio] missing sfx: " << p << std::endl; continue; } @@ -114,7 +114,7 @@ bool AudioManager::loadMusic(BiomeType biome, const std::string& path) { } void AudioManager::loadAllAssets() { - // Footsteps โ€” variations make the loop sound less robotic. + // Footsteps - variations make the loop sound less robotic. loadSfx(SoundId::Footstep_Grass, { "assets/sounds/footsteps/grass/grass1.wav", "assets/sounds/footsteps/grass/grass2.wav", @@ -171,7 +171,7 @@ void AudioManager::loadAllAssets() { "assets/sounds/liquids/splash2.wav", }); - // Block break / place โ€” keyed by material group. + // Block break / place - keyed by material group. loadSfx(SoundId::Break_Stone, { "assets/sounds/blocks/stone/stone1.wav", "assets/sounds/blocks/stone/stone2.wav", @@ -251,7 +251,7 @@ void AudioManager::loadAllAssets() { "assets/sounds/blocks/snow/snow4.wav", }); - // Mobs. Filenames here mirror what's actually on disk under assets/sounds/mobs/ โ€” + // Mobs. Filenames here mirror what's actually on disk under assets/sounds/mobs/ - // zombies have their own per-step set; creepers reuse the player's material footsteps. loadSfx(SoundId::Zombie_Idle, { "assets/sounds/mobs/zombie/say1.wav", @@ -474,7 +474,7 @@ SoundId AudioManager::hurtSoundFor(LivingEntityType t) { } bool AudioManager::blockSfxSuppressed(glm::dvec3 worldPos) const { - // Linear scan โ€” windows live for <1s and there's almost never more than 1 active at a time. + // Linear scan - windows live for <1s and there's almost never more than 1 active at a time. for (const auto& w : explosionWindows) { glm::dvec3 d = worldPos - w.pos; double r = static_cast(w.radius); @@ -594,7 +594,7 @@ void AudioManager::setBiome(BiomeType newBiome) { void AudioManager::crossfadeTo(BiomeType b, float seconds) { auto it = musicCache.find(b); if (it == musicCache.end()) { - // No track for this biome โ€” just fade the current one out. + // No track for this biome - just fade the current one out. if (activeMusicHandle) { engine.fadeVolume(activeMusicHandle, 0.0f, seconds); engine.scheduleStop(activeMusicHandle, seconds); @@ -700,7 +700,7 @@ void AudioManager::applyVolumes() { // --------------------------------------------------------------------------- void AudioManager::update(float deltaTime, bool isPlaying, Camera& cam, Renderer& world) { - // In menus: pause music, skip emitter logic. Don't deinit โ€” resume is instant on return. + // In menus: pause music, skip emitter logic. Don't deinit - resume is instant on return. if (!isPlaying) { if (activeMusicHandle && !musicPaused) { engine.setPause(activeMusicHandle, true); @@ -721,7 +721,7 @@ void AudioManager::update(float deltaTime, bool isPlaying, Camera& cam, Renderer glm::vec3 up = player->WorldUp; // Listener velocity is forced to zero (no doppler). Real player velocity spikes // hard during creeper-explosion knockback / fall recovery, and SoLoud's doppler then - // pitch-shifts every active 3D voice โ€” heard as a "crackle" during/after the blast. + // pitch-shifts every active 3D voice - heard as a "crackle" during/after the blast. // Doppler isn't worth those artifacts in a survival game. glm::vec3 vel = glm::vec3(0.0f); @@ -770,15 +770,15 @@ void AudioManager::updateFootsteps(float dt, Camera& cam, Renderer& world) { // so it lines up with `speed * dt` distance accumulation below. glm::vec3 pvel = cam.getLatestSnapshot().velocity * TPS; - // Horizontal speed only โ€” we don't want the y-axis fall to count as walking. + // Horizontal speed only - we don't want the y-axis fall to count as walking. glm::vec2 horiz(pvel.x, pvel.z); float speed = glm::length(horiz); - // The local player's own sounds are 2D โ€” playing them as 3D emitters at the feet + // The local player's own sounds are 2D - playing them as 3D emitters at the feet // while the listener sits at the eyes makes every step pan slightly below-and-behind // Detect water entry โ†’ splash one-shot. Use prevFallDist (latched at the bottom of this - // function from last frame's accumulatedFallDistance) โ€” by the time the underwater edge + // function from last frame's accumulatedFallDistance) - by the time the underwater edge // fires, the server has likely already zeroed the counter, same hazard the fall-landing // block below documents. Threshold matches Player_FallBig's 4-block fall-damage boundary. bool underwater = world.isUnderwater(ppos); @@ -797,7 +797,7 @@ void AudioManager::updateFootsteps(float dt, Camera& cam, Renderer& world) { } // Fall-impact rising edge: was airborne, just touched ground. Use the *previous* frame's - // accumulatedFallDistance because the server resets it to 0 on landing โ€” by the time we see + // accumulatedFallDistance because the server resets it to 0 on landing - by the time we see // onGround=true the counter is already 0. Thresholds match vanilla: // >=4 blocks โ†’ fallbig (matches the SAFE_FALL_DISTANCE+1 boundary that triggers damage) // >=2.0 โ†’ fallsmall (just a thump, no damage) @@ -845,7 +845,7 @@ void AudioManager::updateFootsteps(float dt, Camera& cam, Renderer& world) { // Sample the block one cell below the player's feet to pick the right material. glm::ivec3 below = glm::ivec3(glm::floor(ppos)) + glm::ivec3(0, -1, 0); BlockType ground = world.getBlockWorld(below); - if (ground == BlockType::AIR) return; // stepping over a hole โ€” skip the click + if (ground == BlockType::AIR) return; // stepping over a hole - skip the click playSfx2D(footstepFor(ground), 0.5f); } @@ -856,7 +856,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { // // The local player lives on Camera (not in `livingEntities`), so iterating this list is // effectively "everyone but me". Server packets don't carry velocity (NetEntityMove), so - // we derive horizontal speed from successive snapshot positions โ€” same trick as the player + // we derive horizontal speed from successive snapshot positions - same trick as the player // branch above. // Stall guard: a long frame (loading screen, freeze, world unload, big teleport) would otherwise @@ -872,7 +872,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { } // Tick down active explosion suppression windows (set when a primed creeper vanishes below). - // Windows are typically 0.5โ€“0.8s โ€” long enough to swallow the crater's MODIFIED_BLOCK_DATA + // Windows are typically 0.5โ€“0.8s - long enough to swallow the crater's MODIFIED_BLOCK_DATA // burst that arrives over the following few packets without muting unrelated mining nearby. for (auto it = explosionWindows.begin(); it != explosionWindows.end(); ) { it->ttl -= dt; @@ -884,16 +884,16 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { const void* localKey = localPlayer.get(); // Listener position for the per-mob audibility gate. One-shots beyond kAttenMax are killed - // by SoLoud's inaudible-behavior, but only after one buffer fires โ€” that buffer is the + // by SoLoud's inaudible-behavior, but only after one buffer fires - that buffer is the // "split-second of zombie death" the player hears when a mob dies far away. Skip them here. const glm::dvec3 listenerPos = cam.getEyePosD(); const double kAudibleD2 = static_cast(kAttenMax) * static_cast(kAttenMax); for (auto& wle : world.livingEntities) { - // livingEntities is std::vector> โ€” already strong refs. + // livingEntities is std::vector> - already strong refs. auto le = wle; if (!le) continue; - if (le.get() == localKey) continue; // skip self (defensive โ€” not normally present) + if (le.get() == localKey) continue; // skip self (defensive - not normally present) const void* key = le.get(); MobAudioState& st = mobStates[key]; @@ -938,7 +938,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { // ---- footstep stride accumulator (on-ground only) ------------------ if (le->snapshots.empty() || !le->isOnGround()) - st.footstepDist = 0.0f; // airborne or no data โ€” reset stride accumulator + st.footstepDist = 0.0f; // airborne or no data - reset stride accumulator else st.footstepDist += horizDelta; @@ -966,7 +966,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { } } - // ---- water audio (PLAYER only โ€” splash on entry, swim while submerged) --- + // ---- water audio (PLAYER only - splash on entry, swim while submerged) --- // Mirrors the local-player branch in updateFootsteps(), but emitted as 3D one-shots at // the remote player's position so they pan/attenuate from the listener's POV. if (st.type == PLAYER) { @@ -974,7 +974,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { float curFallDist = le->getAccumulatedFallDistance(); // Water-entry rising edge โ†’ splash (random of 2 variations) or heavy splash on a - // fall-damage-threshold drop. Read prevFallDist (last frame's value) โ€” server zeroes + // fall-damage-threshold drop. Read prevFallDist (last frame's value) - server zeroes // accumulatedFallDistance on contact with water, same hazard the local code documents. if (underwater && !st.prevUnderwater && audible) { if (st.prevFallDist >= 4.0f) @@ -983,7 +983,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { playSfx3D(SoundId::Player_Splash, epos, glm::vec3(0.0f), 0.4f); } - // Swim strokes โ€” accumulate horizontal travel ignoring isOnGround() (you're floating + // Swim strokes - accumulate horizontal travel ignoring isOnGround() (you're floating // in water, not standing on the bottom). One stroke per kSwimStrokeM blocks. if (underwater) { st.swimDistance += horizDelta; @@ -1015,13 +1015,13 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { SoundId idleId = (st.type == ZOMBIE) ? SoundId::Zombie_Idle : SoundId::Creeper_Idle; playSfx3D(idleId, epos, glm::vec3(0.0f), 0.5f); } - // 6โ€“14 s โ€” vanilla cadence. Random within range so two nearby mobs don't sync. + // 6โ€“14 s - vanilla cadence. Random within range so two nearby mobs don't sync. st.idleCooldown = 6.0f + frand01() * 8.0f; } // Creeper fuse rising-edge. clientPrimed is mirrored from NetEntityMove's 0x08 flag. // Track the SoLoud handle so we can stop the (long) fuse sample when the creeper - // unprimes, dies, or explodes โ€” otherwise the voice keeps playing at its old position + // unprimes, dies, or explodes - otherwise the voice keeps playing at its old position // and glitches when the listener jumps (e.g. you die mid-fuse and respawn far away). if (st.type == CREEPER) { bool primed = false; @@ -1039,7 +1039,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { } // ---- death / explode sweep ------------------------------------------------- - // Anything in `mobStates` that's no longer in `livingEntities` just disappeared this frame โ€” + // Anything in `mobStates` that's no longer in `livingEntities` just disappeared this frame - // fire the appropriate one-shot before erasing. Creepers that exploded were primed at vanish // time; otherwise it's a regular death. Distance-gated to kAttenMax so a zombie dying past // the audible envelope doesn't pop one buffer of "uggh!" before SoLoud kills the voice. @@ -1060,7 +1060,7 @@ void AudioManager::updateMobAudio(float dt, Camera& cam, Renderer& world) { bool deathAudible = glm::dot(d, d) <= kAudibleD2; // Fallback for anything that bypassed App.cpp's immediate death-sound path - // (which sets deathSoundFired). diedByExplosion picks Explode vs Death โ€” a + // (which sets deathSoundFired). diedByExplosion picks Explode vs Death - a // primed creeper killed mid-fuse plays Death, not Explode. if (!st.deathSoundFired) { switch (st.type) { diff --git a/src/client/Camera.cpp b/src/client/Camera.cpp index 9402ca2e..8138c731 100644 --- a/src/client/Camera.cpp +++ b/src/client/Camera.cpp @@ -151,16 +151,16 @@ static double ddaFirstSolidHit(const Renderer &world, sideDist[axis] += deltaDist[axis]; const BlockType b = world.getBlockWorld(blockPos); - // END = chunk not loaded โ€” don't trap the camera against missing geometry. + // END = chunk not loaded - don't trap the camera against missing geometry. if (b != BlockType::END && isBlockSolid(b)) return entryDist; } } // Pull the third-person camera in toward the player when a solid block sits -// between them, so the view never goes through terrain. Sweep five rays โ€” the +// between them, so the view never goes through terrain. Sweep five rays - the // central eyeโ†’camera ray plus four offset by ยฑkProbeRadius perpendicular to -// it โ€” so lateral geometry beside the camera (a wall just to the side, a +// it - so lateral geometry beside the camera (a wall just to the side, a // corner, etc.) shrinks the offset too. A single ray missed those cases and // left the near plane poking through walls. // @@ -205,7 +205,7 @@ void Camera::updateThirdPersonCollision(const Renderer &world, float deltaTime) glm::dvec3 right = glm::cross(rayDir, worldUp); double rLen = glm::length(right); if (rLen < 1e-6) { - // rayDir is parallel to worldUp (looking straight up/down) โ€” use any + // rayDir is parallel to worldUp (looking straight up/down) - use any // perpendicular axis to avoid a degenerate basis. right = glm::dvec3(1.0, 0.0, 0.0); } else { @@ -214,7 +214,7 @@ void Camera::updateThirdPersonCollision(const Renderer &world, float deltaTime) const glm::dvec3 up = glm::cross(right, rayDir); // already unit length // Probe radius approximates the camera frustum's lateral extent at the near - // plane. At FOV 80ยฐ and near 0.1 the near-plane half-width is ~0.15 โ€” pad + // plane. At FOV 80ยฐ and near 0.1 the near-plane half-width is ~0.15 - pad // a bit so the swept volume covers the corners with a small skin. constexpr double kProbeRadius = 0.25; @@ -239,7 +239,7 @@ void Camera::updateThirdPersonCollision(const Renderer &world, float deltaTime) static_cast((hitDistance - kCameraSkin) / fullLen), 0.0f, 1.0f); if (targetFraction < cameraDistanceFraction) { - // Snap in โ€” collision must take effect this frame. + // Snap in - collision must take effect this frame. cameraDistanceFraction = targetFraction; } else { // Ease back out so the camera doesn't pop when a block clears. @@ -418,7 +418,7 @@ void Camera::reconcile(const PredictedStates &correction, int32_t clientTick, co } // Health is not simulated client-side for PvP/explosion damage, so a position-only - // match would silently drop the server's authoritative health update โ€” including the + // match would silently drop the server's authoritative health update - including the // killing blow that should trigger the death screen. const bool healthMatches = std::abs(it->health - effectiveCorrection.health) < 0.001f; @@ -438,7 +438,7 @@ void Camera::reconcile(const PredictedStates &correction, int32_t clientTick, co } } - // Guard: stale correction older than oldest history entry โ€” already processed + // Guard: stale correction older than oldest history entry - already processed if (!predictedStates.empty() && effectiveCorrection.serverClientReconciliationTick < predictedStates.front().serverClientReconciliationTick) { @@ -522,7 +522,7 @@ void Camera::reconcile(const PredictedStates &correction, int32_t clientTick, co if (horizontalPosErr > reconcilePosErrorThreshold || verticalPosErr > reconcilePosErrorThreshold || velocityErr > reconcileVelErrorThreshold) { // Smooth visual popping by setting a bounded camera offset that decays over time. - // Computed in double then downcast โ€” the diff itself is small (sub-block). + // Computed in double then downcast - the diff itself is small (sub-block). glm::dvec3 desiredVisualOffsetD = oldCurrentState.position - reconciledCurrentState.position; constexpr float kMaxVisualOffset = 0.35f; const float desiredLen = static_cast(glm::length(desiredVisualOffsetD)); @@ -571,7 +571,7 @@ void Camera::onSnapshot(NetPlayerMove &pkt) // Normally we skip snapshots whose ack tick we've already processed. But the server's // ack tick is frozen while the player is dead (inputs are blocked), so the killing-blow - // snapshot โ€” and the respawn snapshot โ€” share the same tick as the last pre-death one. + // snapshot - and the respawn snapshot - share the same tick as the last pre-death one. // Accept those by letting health changes through even when the tick hasn't advanced. if (lastAppliedServerClientReconciliationTick != -1 && ((long)(pkt.serverClientReconciliationTick) - (long)(lastAppliedServerClientReconciliationTick) <= 0) diff --git a/src/client/ChunkRenderer.cpp b/src/client/ChunkRenderer.cpp index 3fb496ac..c89c5bad 100644 --- a/src/client/ChunkRenderer.cpp +++ b/src/client/ChunkRenderer.cpp @@ -1,7 +1,7 @@ #include "ChunkRenderer.hpp" -// Default to "Smart" โ€” keep alpha cutouts on outer leaf surfaces, but cull +// Default to "Smart" - keep alpha cutouts on outer leaf surfaces, but cull // the wasted internal faces. Closest match to the original look at a fraction // of the vertex count. ChunkRenderer::LeafRenderMode ChunkRenderer::sLeafRenderMode = ChunkRenderer::LeafRenderMode::Smart; @@ -253,7 +253,7 @@ void ChunkRenderer::buildMeshData() { // sea-level plane goes to the "ocean" bucket: that's the face the // planar reflection/refraction FBOs were rendered for. Side faces of // the same sea-level block, placed/spread water, and deeper top faces - // all go to the sky-reflection bucket โ€” that shader is independent of + // all go to the sky-reflection bucket - that shader is independent of // any global plane and works for arbitrarily-oriented water. const int waterSurfaceY = sSeaLevel; @@ -287,16 +287,16 @@ void ChunkRenderer::buildMeshData() { // Look up the sky-light value for a face. // // We want the light level of the AIR block that the face is - // exposed to โ€” that tells us how much sky exposure this face has. + // exposed to - that tells us how much sky exposure this face has. // // For faces within this chunk: straightforward array lookup. // // For faces at chunk borders: we read the adjacent chunk's // skyLight array. This is safe because computeSkyLight() uses - // std::swap โ€” the member array is either the previous fully- + // std::swap - the member array is either the previous fully- // computed result or the new one, never a partial write. // If the neighbor hasn't computed skyLight yet (empty array), - // getSkyLight() returns 15 (assume sunlit โ€” corrected on rebuild). + // getSkyLight() returns 15 (assume sunlit - corrected on rebuild). auto getSkyLightForFace = [&](int blockX, int blockY, int blockZ, int dx, int dy, int dz, Direction dir) -> uint8_t { @@ -372,7 +372,7 @@ void ChunkRenderer::buildMeshData() { // In Fast/Smart, leaves are treated as opaque blocks for mesh-emission // decisions: faces between leaves and other leaves (or between leaves // and other solid blocks) are skipped. In Fancy, leaves stay transparent - // and every face is emitted โ€” the original behaviour. + // and every face is emitted - the original behaviour. const bool leavesAreTransparentForMesh = (sLeafRenderMode == LeafRenderMode::Fancy); @@ -385,7 +385,7 @@ void ChunkRenderer::buildMeshData() { if (currentBlock == BlockType::AIR) continue; if (isBlockVegetation(currentBlock)) continue; - // Torches aren't part of the chunk mesh โ€” the packed-vertex + // Torches aren't part of the chunk mesh - the packed-vertex // format can't map a partial sprite, so they'd show the whole // torch image on every face. Record them for HeldItemRenderer // to draw with the same voxel-extruded model as the held one. @@ -429,7 +429,7 @@ void ChunkRenderer::buildMeshData() { if (neighborBlock == BlockType::AIR || isBlockTransparent(neighborBlock) || isBlockVegetation(neighborBlock)) { // Only the *top* face of a water block sitting // exactly on the sea-level plane goes into the - // planar-reflection bucket โ€” that face is the one + // planar-reflection bucket - that face is the one // sampled by the reflection/refraction FBOs. // Everything else (side faces of sea-level blocks, // placed/spread water, deeper top faces) uses the @@ -492,9 +492,9 @@ void ChunkRenderer::uploadMesh() { // Packed terrain vertex layout (8 bytes per vertex). Decoded in // shaders/terrain_vertex_decode.glsl. - // location 0: v0 (uint) โ€” pos.x | pos.y | pos.z (1/16 fixed point) - // location 1: v1 (uint) โ€” normal | corner | texLayer | skyLight - // NOTE: glVertexAttribIPointer (the I variant) โ€” integer attributes are + // location 0: v0 (uint) - pos.x | pos.y | pos.z (1/16 fixed point) + // location 1: v1 (uint) - normal | corner | texLayer | skyLight + // NOTE: glVertexAttribIPointer (the I variant) - integer attributes are // delivered as uint without the float conversion path. GLsizei stride = sizeof(PackedVertex); glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, stride, reinterpret_cast(offsetof(PackedVertex, v0))); @@ -506,7 +506,7 @@ void ChunkRenderer::uploadMesh() { meshVertices.clear(); meshVertices.shrink_to_fit(); - // Upload water mesh โ€” same packed format. + // Upload water mesh - same packed format. if (!waterMeshVertices.empty()) { if (waterVAO == 0) glGenVertexArrays(1, &waterVAO); @@ -530,7 +530,7 @@ void ChunkRenderer::uploadMesh() { waterMeshVertices.clear(); waterMeshVertices.shrink_to_fit(); - // Upload placed-water mesh โ€” same packed format, separate VAO/VBO so we + // Upload placed-water mesh - same packed format, separate VAO/VBO so we // can bind the simpler sky-reflection shader for it without re-issuing // ocean draws. if (!placedWaterMeshVertices.empty()) { diff --git a/src/client/GBuffer.cpp b/src/client/GBuffer.cpp index e3f0eaf2..5c1378a1 100644 --- a/src/client/GBuffer.cpp +++ b/src/client/GBuffer.cpp @@ -36,7 +36,7 @@ void GBuffer::create() { unsigned int attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; glDrawBuffers(2, attachments); - // Depth texture (sampleable โ€” needed by SSAO to reconstruct view-space position) + // Depth texture (sampleable - needed by SSAO to reconstruct view-space position) glGenTextures(1, &depthTexture); glBindTexture(GL_TEXTURE_2D, depthTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, SCR_WIDTH, SCR_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); diff --git a/src/client/HeldItemRenderer.cpp b/src/client/HeldItemRenderer.cpp index 8b694ad7..76a820ce 100644 --- a/src/client/HeldItemRenderer.cpp +++ b/src/client/HeldItemRenderer.cpp @@ -21,7 +21,7 @@ namespace { -// Per-vertex stride in floats (pos.xyz, uv.xy, texLayer, skyLight) โ€” must match +// Per-vertex stride in floats (pos.xyz, uv.xy, texLayer, skyLight) - must match // the cubePropShader vertex layout and buildCube/buildItemSprite output. constexpr int STRIDE = 8; @@ -73,9 +73,9 @@ glm::mat4 torchUprightFlip(const std::vector& canonical) constexpr float SHOULDER_HEIGHT = 1.394f; constexpr float SHOULDER_RIGHT = 0.348f; constexpr float ARM_LENGTH = 0.697f; -constexpr float ARM_REST_ANGLE = 0.45f; // ~26ยฐ forward โ€” visible held pose at rest +constexpr float ARM_REST_ANGLE = 0.45f; // ~26ยฐ forward - visible held pose at rest // buildCube(isIlluminated=false) emits a 0.2-unit cube centered at (0, 0.1, 0); -// these scales are applied straight to that source size โ€” final cube size in +// these scales are applied straight to that source size - final cube size in // world units is CUBE_SOURCE_SIZE * CUBE_SCALE. constexpr float CUBE_SOURCE_SIZE = 0.2f; constexpr float CUBE_Y_CENTER = 0.1f; // half-height: source verts span y in [0, 0.2] @@ -125,7 +125,7 @@ constexpr float VM_BOB_GAIN_Y = 0.06f; // 1P walking bob, vertical (camera-spac constexpr float VM_BOB_GAIN_X = 0.04f; // 1P walking sway, horizontal // Separate shoulder + elbow rotations for the right arm at the current frame. -// We need both โ€” collapsing them into one angle on a straight arm makes the +// We need both - collapsing them into one angle on a straight arm makes the // hand overshoot vertically during a punch (the bent forearm has a much // shorter "up" reach than a 90ยฐ+30ยฐ straight-arm rotation would have). struct ArmPose { float shoulder; float elbow; }; @@ -226,13 +226,13 @@ void buildWeaponVoxelMesh(std::vector& buf, const float u = (px + 0.5f) * cell; const float vTex = (py + 0.5f) * cell; - // FRONT (+Z) โ€” always visible. + // FRONT (+Z) - always visible. v(x0, y0, z1, u, vTex); v(x1, y0, z1, u, vTex); v(x1, y1, z1, u, vTex); v(x1, y1, z1, u, vTex); v(x0, y1, z1, u, vTex); v(x0, y0, z1, u, vTex); - // BACK (-Z) โ€” always visible (slab is one voxel deep, no neighbors behind). + // BACK (-Z) - always visible (slab is one voxel deep, no neighbors behind). v(x1, y0, z0, u, vTex); v(x0, y0, z0, u, vTex); v(x0, y1, z0, u, vTex); v(x0, y1, z0, u, vTex); v(x1, y1, z0, u, vTex); v(x1, y0, z0, u, vTex); - // TOP (+Y) โ€” emit only if no opaque neighbor in the +Y direction. + // TOP (+Y) - emit only if no opaque neighbor in the +Y direction. if (!opaqueAt(px, py + 1)) { v(x0, y1, z1, u, vTex); v(x1, y1, z1, u, vTex); v(x1, y1, z0, u, vTex); v(x1, y1, z0, u, vTex); v(x0, y1, z0, u, vTex); v(x0, y1, z1, u, vTex); @@ -301,7 +301,7 @@ glm::vec3 itemAnchorRel(const glm::dvec3& worldPos, const glm::dvec3& eyePos, // not just the shoulder), apply cube-local tilts for a readable 3-face view, // scale, and recenter. // buildCube here outputs a 0.2-unit cube centered at (0, CUBE_Y_CENTER, 0), -// not a 0..1 cube โ€” so the recenter step only nudges Y, never -0.5 on all axes. +// not a 0..1 cube - so the recenter step only nudges Y, never -0.5 on all axes. glm::mat4 cubeModelMatrix(const glm::vec3& anchorRel, float yawRad, ArmPose pose, float scale) { @@ -313,7 +313,7 @@ glm::mat4 cubeModelMatrix(const glm::vec3& anchorRel, float yawRad, M = glm::rotate(M, -yawRad, glm::vec3(0.0f, 1.0f, 0.0f)); // Cube follows the forearm's world rotation around player-right. M = glm::rotate(M, forearmAngle, glm::vec3(0.0f, 0.0f, 1.0f)); - // Cube-local presentation tilts โ€” applied in the cube's own frame so the + // Cube-local presentation tilts - applied in the cube's own frame so the // three-face view is preserved through every yaw / arm-swing pose. M = glm::rotate(M, TP_REST_TILT_Y, glm::vec3(0.0f, 1.0f, 0.0f)); M = glm::rotate(M, TP_REST_TILT_X, glm::vec3(1.0f, 0.0f, 0.0f)); @@ -605,7 +605,7 @@ void HeldItemRenderer::drawPlacedTorches(const glm::mat4& projection, const glm: // Canonical mesh bbox. buildWeaponVoxelMesh maps texture columnโ†’X and // rowโ†’Y with row 0 (image TOP = flame) at small Y, so the model's +Y - // points toward the torch BASE โ€” we reflect Y to stand it flame-up. + // points toward the torch BASE - we reflect Y to stand it flame-up. float minX = 1e9f, maxX = -1e9f, minY = 1e9f, maxY = -1e9f; for (std::size_t i = 0; i + 6 < canonical->size(); i += STRIDE) { minX = std::min(minX, (*canonical)[i + 0]); @@ -617,7 +617,7 @@ void HeldItemRenderer::drawPlacedTorches(const glm::mat4& projection, const glm: const float modelH = std::max(maxY - minY, 1e-3f); // C: centre X on the post, base at local origin. Model +Y already points - // up (flame at top), so no Y reflection โ€” just shift minY to 0. + // up (flame at top), so no Y reflection - just shift minY to 0. glm::mat4 C(1.0f); C[3] = glm::vec4(-cx, -minY, 0.0f, 1.0f); @@ -669,7 +669,7 @@ void HeldItemRenderer::drawForEntities(const glm::mat4& projection, const glm::m cpuBuffer.clear(); int itemCount = 0; - // Local player isn't in renderer->livingEntities โ€” feed it in here so its + // Local player isn't in renderer->livingEntities - feed it in here so its // hand renders in third-person. if (localPlayer && itemCount < MAX_ITEMS) { glm::dvec3 worldPos = localPlayer->getPositionD(); @@ -775,7 +775,7 @@ void HeldItemRenderer::drawWeaponsForEntities(const glm::mat4& projection, const // Map the canonical mesh's diagonal hiltโ†’tip onto -along (so the // blade points AWAY from the hand toward the tip, since canonical - // hilt-corner is at (1, 0) and tip-corner is at (0, 1) โ€” i.e. + // hilt-corner is at (1, 0) and tip-corner is at (0, 1) - i.e. // canonical (-1, 1, 0) direction is the hiltโ†’tip diagonal). // We send canonical (-1, 1, 0) to along, canonical (0, 0, 1) to // sideOrtho (blade thickness across the side of the body), and pick @@ -871,7 +871,7 @@ void HeldItemRenderer::drawFirstPerson(const glm::mat4& projection, ItemType type = itemIDToItemType(heldItemType); const std::size_t start = cpuBuffer.size(); - // Weapons get a dedicated per-pixel-extruded mesh path โ€” a true 3D + // Weapons get a dedicated per-pixel-extruded mesh path - a true 3D // sword-shaped voxel mesh instead of a slab-with-paint. The vert count is // variable (depends on the weapon's silhouette), so this path uses its // own VAO/VBO and bypasses the 36-vert/item slot entirely. @@ -980,7 +980,7 @@ void HeldItemRenderer::drawFirstPerson(const glm::mat4& projection, shader->setMat4("projection", projection); shader->setMat4("viewRot", viewRot); - // Always-on-top: clear depth (force mask on first โ€” clouds composite may + // Always-on-top: clear depth (force mask on first - clouds composite may // have left it disabled), then keep depth test enabled for cube self-sort. glDepthMask(GL_TRUE); glClear(GL_DEPTH_BUFFER_BIT); diff --git a/src/client/Lighting.cpp b/src/client/Lighting.cpp index 01b7e3ed..7f9e5fdc 100644 --- a/src/client/Lighting.cpp +++ b/src/client/Lighting.cpp @@ -153,7 +153,7 @@ void Lighting::renderCloudsLowRes(const glm::mat4& view, const glm::mat4& projec glm::vec3 sunDirNorm = glm::normalize(getDirectionalLightDirection()); float sunElevation = sunDirNorm.y; // Can be negative (below horizon) float dayFactor = glm::smoothstep(-0.2f, 0.1f, sunElevation); // Fade from -0.2 to 0.1 - // Very dim night ambient โ€” auto-exposure + gamma encode lifts dark linear + // Very dim night ambient - auto-exposure + gamma encode lifts dark linear // values a lot in display space, so the linear floor has to stay tiny. float nightAmbient = 0.002f; float dayAmbient = 0.5f; @@ -240,7 +240,7 @@ void Lighting::drawSky(const glm::mat4& view, const glm::mat4& projection, glm:: glm::vec3 Lighting::getAnimatedLightCubePosition(int i) const { if (i < 0 || i >= 3) return glm::vec3(0.0f); - // Shared centroid of the three configured positions โ€” the swirl orbits + // Shared centroid of the three configured positions - the swirl orbits // around it, so if any cube is repositioned via setPointLightPosition // the formation re-centers naturally. const glm::vec3 center = (pointLightPositions[0] @@ -256,7 +256,7 @@ glm::vec3 Lighting::getAnimatedLightCubePosition(int i) const { const float a = t * orbitSpeed + phase; // Tilted ring whose tilt slowly breathes and whose tilt axis precesses - // around Y โ€” the plane wobbles instead of staying flat. + // around Y - the plane wobbles instead of staying flat. const float tilt = glm::radians(35.0f) + std::sin(t * 0.3f) * glm::radians(20.0f); const float yaw = t * 0.15f; @@ -296,7 +296,7 @@ void Lighting::compositeCloudsToBackbuffer(GLuint sceneColorTex, GLuint sceneDep cloudCompositeShader->setInt("sceneDepth", TextureUnits::SCENE_DEPTH); // Cloud texture (low-res RGBA from the volumetric march). If clouds are disabled - // or the FBO isn't ready, bind 0 โ€” the shader's cloudOpacity early-out handles it. + // or the FBO isn't ready, bind 0 - the shader's cloudOpacity early-out handles it. glActiveTexture(GL_TEXTURE0 + TextureUnits::CLOUDS); glBindTexture(GL_TEXTURE_2D, getCloudTexture()); cloudCompositeShader->setInt("cloudTex", TextureUnits::CLOUDS); @@ -348,7 +348,7 @@ void Lighting::drawLightCubes(const glm::mat4& view, const glm::mat4& projection auto model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(posRelD)); - // Tumble on two arbitrary, non-orthogonal axes at different rates โ€” + // Tumble on two arbitrary, non-orthogonal axes at different rates - // the composition gives a constantly-shifting orientation. model = glm::rotate(model, t * 1.5f + phase, glm::normalize(glm::vec3(0.5f, 1.0f, 0.3f))); @@ -374,7 +374,7 @@ void Lighting::drawLightCubes(const glm::mat4& view, const glm::mat4& projection GLboolean prevDepthMask; glGetBooleanv(GL_DEPTH_WRITEMASK, &prevDepthMask); GLboolean prevBlend = glIsEnabled(GL_BLEND); - // Capture RGB and alpha factors separately โ€” the caller may have set + // Capture RGB and alpha factors separately - the caller may have set // them via glBlendFuncSeparate with differing values, and restoring with // plain glBlendFunc would silently collapse RGB to whatever the alpha // factors were. We restore with glBlendFuncSeparate below. @@ -390,7 +390,7 @@ void Lighting::drawLightCubes(const glm::mat4& view, const glm::mat4& projection const int N = kLightCubeTrailLength; // Newest written slot is (head - 1). k=1 is one frame behind the live - // cube โ€” skip k=0 since that's exactly where the main cube already drew. + // cube - skip k=0 since that's exactly where the main cube already drew. for (unsigned int i = 0; i < 3; ++i) { if (!pointLightsOn[i]) continue; const glm::vec3 baseCol = pointLightDiffuse[i]; @@ -403,7 +403,7 @@ void Lighting::drawLightCubes(const glm::mat4& view, const glm::mat4& projection // age โˆˆ [0,1]: 0 = newest tail segment, 1 = oldest. const float age = static_cast(k) / static_cast(N - 1); - // Quadratic fade โ€” bright near the head, fast falloff into the tail. + // Quadratic fade - bright near the head, fast falloff into the tail. const float fade = (1.0f - age) * (1.0f - age); const float scale = 0.16f * (0.25f + 0.75f * fade); @@ -417,7 +417,7 @@ void Lighting::drawLightCubes(const glm::mat4& view, const glm::mat4& projection glm::normalize(glm::vec3(0.5f, 1.0f, 0.3f))); model = glm::scale(model, glm::vec3(scale)); - // Brightness scaled by fade โ€” additive blending then makes the + // Brightness scaled by fade - additive blending then makes the // newest segments dominate while the tail melts into the scene. lightCubeShader->setVec3("cubeColor", baseCol * fade * 0.7f); lightCubeShader->setMat4("model", model); @@ -521,7 +521,7 @@ void Lighting::uploadLightingUniforms(const Shader &shader, const glm::dvec3 &ey // The following code implements both steps each frame. shader.use(); - // set light uniforms โ€” subtract in double then narrow, otherwise far-from-origin + // set light uniforms - subtract in double then narrow, otherwise far-from-origin // coords lose precision via catastrophic cancellation in the f32 difference. shader.setVec3("viewPos", glm::vec3(0.0f)); shader.setVec3("lightPos", glm::vec3(glm::dvec3(lightPos) - eyePos)); @@ -566,7 +566,7 @@ void Lighting::uploadLightingUniforms(const Shader &shader, const glm::dvec3 &ey // HDR mode gives us headroom above 1.0: push direct sun and daytime ambient // higher so the final tonemap has real dynamic range and shadowed areas // stay readable. Both boosts are blended in with `day` so they fade to 1.0 - // at night โ€” without this, the night ambient comes out 1.6ร— brighter than + // at night - without this, the night ambient comes out 1.6ร— brighter than // the pre-HDR look, and auto-exposure then makes night feel like day. const float ambientBoost = hdrEnabled ? glm::mix(1.0f, 1.6f, day) : 1.0f; const float diffuseBoost = hdrEnabled ? glm::mix(1.0f, 1.8f, day) : 1.0f; @@ -850,7 +850,7 @@ void Lighting::drawCSMDebugView(const glm::vec3& cameraPos, const glm::vec3& cam // The 8 corners of the NDC cube [-1,1]^3, transformed by inverse(lightSpaceMatrix), give the world-space ortho box if (showLightFrustums && c < static_cast(csmLightSpaceMatrices.size())) { auto lightCorners = getFrustumCornersWorldSpace( - glm::mat4(1.0f), // identity view โ€” the lightSpaceMatrix already includes both proj and view + glm::mat4(1.0f), // identity view - the lightSpaceMatrix already includes both proj and view csmLightSpaceMatrices[c] ); // Note: getFrustumCornersWorldSpace computes inv(proj * view), so passing (identity, lsm) @@ -1230,7 +1230,7 @@ void Lighting::initCSMResources() glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - // FBO โ€” layer attachment is done per-pass in updateCSMShadowMaps() + // FBO - layer attachment is done per-pass in updateCSMShadowMaps() glGenFramebuffers(1, &csmFBO); glBindFramebuffer(GL_FRAMEBUFFER, csmFBO); @@ -1304,7 +1304,7 @@ void Lighting::setShadowFarPlane(float farPlane) { if (farPlane == cameraFarPlane) return; cameraFarPlane = farPlane; - // Splits scale with the far plane โ€” recompute to stay proportional. + // Splits scale with the far plane - recompute to stay proportional. recomputeCascadeSplits(); // Texture array dimensions don't depend on far plane, so no rebuild needed. } diff --git a/src/client/Renderer.cpp b/src/client/Renderer.cpp index 670297a8..c4b05a22 100644 --- a/src/client/Renderer.cpp +++ b/src/client/Renderer.cpp @@ -183,7 +183,7 @@ void Renderer::organizeChunks(const std::pair pos, int loadRadius, flo // Don't evict chunks that arrived in the last few seconds: the player // position can lag a teleport/respawn by a handful of frames (NetPlayerMove // is unreliable), and during that window freshly-received chunks would be - // erased by distance even though the server already marked them sent โ€” so + // erased by distance even though the server already marked them sent - so // they'd never be re-streamed and the area would have permanent holes. constexpr auto RECENT_CHUNK_GRACE = std::chrono::seconds(3); const auto now = std::chrono::steady_clock::now(); @@ -209,7 +209,7 @@ void Renderer::organizeChunks(const std::pair pos, int loadRadius, flo auto rt = chunkReceiveTime.find(chunkPos); if (rt != chunkReceiveTime.end() && now - rt->second < RECENT_CHUNK_GRACE) { - // Recently arrived โ€” keep it; player position may still be + // Recently arrived - keep it; player position may still be // catching up after a teleport/respawn. ++it; } @@ -347,7 +347,7 @@ void Renderer::updateVegetationUniforms(const glm::mat4& view, const glm::mat4& vegetationShader->setMat4("projection", projection); vegetationShader->setVec4("clipPlane", clipPlane); vegetationShader->setVec3("viewPos", viewPos); - // Graphics-quality knobs โ€” uploaded here too so vegetation in water + // Graphics-quality knobs - uploaded here too so vegetation in water // refraction respects the same sway/density settings as the main pass. vegetationShader->setInt ("vegetationSwayQuality", vegetationSwayQuality); vegetationShader->setFloat("vegetationSwayMaxDist", vegetationSwayMaxDistance); @@ -435,7 +435,7 @@ void Renderer::renderVegetationOnly(const glm::mat4& view, const glm::dvec3& eye const glm::dvec3 chunkOriginWorldD(static_cast(chunk->getOriginX()), 0.0, static_cast(chunk->getOriginZ())); const glm::dvec3 chunkRelD = chunkOriginWorldD - cameraPos; - // Vegetation distance cap โ€” separate from terrain so the user can + // Vegetation distance cap - separate from terrain so the user can // keep distant terrain visible while killing distant leaf overdraw. if (vegMaxDistSq > 0.0f) { const float dSq = static_cast(chunkRelD.x * chunkRelD.x + chunkRelD.z * chunkRelD.z); @@ -513,7 +513,7 @@ void Renderer::renderShadow(const std::shared_ptr &shaderProgram, const clipMaxZ < -1.0f || clipMinZ > 1.0f) continue; - // Mesh is in chunk-local space โ€” supply the world origin so the + // Mesh is in chunk-local space - supply the world origin so the // vertex shader can reconstruct world positions before projecting // into the light's clip space. const glm::dvec3 chunkOriginWorldD(static_cast(chunk->getOriginX()), 0.0, @@ -562,7 +562,7 @@ void Renderer::onEntity(NetEntityMove &pkt, double serverTime) ent->hasHorizontalInput = (pkt.positionFlags & 0x01) != 0; ent->setOnGround((pkt.positionFlags & 0x02) != 0); // IClientEntity virtually inherits LivingEntity (the diamond with Creeper - // forces it), so static_pointer_cast can't cross the virtual base โ€” the + // forces it), so static_pointer_cast can't cross the virtual base - the // downcast needs RTTI. Done once here and reused for arm swing / death / // creeper below. Hoisting triggerArmSwing+triggerDeath onto Entity would // dodge the cast, but they're animation hooks meaningless for items and @@ -592,7 +592,7 @@ void Renderer::onEntity(NetEntityMove &pkt, double serverTime) { if (ice) { - // Latch the explosion flag before the audio layer reads it next frame โ€” + // Latch the explosion flag before the audio layer reads it next frame - // otherwise the death sweep can't tell "killed while primed" from "fuse expired". if (auto le = std::dynamic_pointer_cast(ent)) le->diedByExplosion = (pkt.positionFlags & 0x20) != 0; diff --git a/src/client/SSAO.cpp b/src/client/SSAO.cpp index 952d6228..9ca8d6b9 100644 --- a/src/client/SSAO.cpp +++ b/src/client/SSAO.cpp @@ -93,7 +93,7 @@ void SSAO::generateFramebuffers() { if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cerr << "ERROR::SSAO::FRAMEBUFFER_NOT_COMPLETE" << std::endl; - // Blur FBO โ€” at full resolution for smooth upscaling + // Blur FBO - at full resolution for smooth upscaling glGenFramebuffers(1, &ssaoBlurFBO); glBindFramebuffer(GL_FRAMEBUFFER, ssaoBlurFBO); glGenTextures(1, &ssaoBlurTexture); @@ -174,7 +174,7 @@ void SSAO::renderSSAO(const GBuffer& gBuffer, const glm::mat4& projection) { } void SSAO::blurSSAO() { - // Blur FBO is always at full resolution โ€” this upsamples half-res SSAO + // Blur FBO is always at full resolution - this upsamples half-res SSAO glBindFramebuffer(GL_FRAMEBUFFER, ssaoBlurFBO); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); glClear(GL_COLOR_BUFFER_BIT); diff --git a/src/client/SkyLUT.cpp b/src/client/SkyLUT.cpp index 99876d4f..b4dbd84d 100644 --- a/src/client/SkyLUT.cpp +++ b/src/client/SkyLUT.cpp @@ -16,7 +16,7 @@ SkyLUT::~SkyLUT() { } void SkyLUT::createResources() { - // LUT texture โ€” RGBA16F for Rayleigh (RGB) + Mie (A) + // LUT texture - RGBA16F for Rayleigh (RGB) + Mie (A) glGenTextures(1, &lutTexture); glBindTexture(GL_TEXTURE_2D, lutTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, LUT_WIDTH, LUT_HEIGHT, 0, GL_RGBA, GL_FLOAT, nullptr); diff --git a/src/client/TerrainDebugWindow.cpp b/src/client/TerrainDebugWindow.cpp index b2aa15c0..db85688e 100644 --- a/src/client/TerrainDebugWindow.cpp +++ b/src/client/TerrainDebugWindow.cpp @@ -46,7 +46,7 @@ void TerrainDebugWindow::setRegenerateCallback(void(*callback)(void*), void* use } // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Noise helpers โ€” mirror ChunkGeneration private methods exactly +// Noise helpers - mirror ChunkGeneration private methods exactly // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ void TerrainDebugWindow::reseedNoise(int32_t seed) { @@ -229,15 +229,15 @@ void TerrainDebugWindow::updateTexture(const TerrainGenerationParams& params) { uint8_t r, g, b; if (h < sl) { - // Below sea level โ€” actual water. Distinguish river/lake from plain ocean. + // Below sea level - actual water. Distinguish river/lake from plain ocean. if (riverMask > 0.05f) { - // River water โ€” vivid cyan-blue + // River water - vivid cyan-blue float t = glm::clamp(riverMask, 0.0f, 1.0f); r = (uint8_t)(20 + (1.0f - t) * 30); g = (uint8_t)(120 + t * 60); b = (uint8_t)(230 - t * 30); } else if (lakeMask > 0.05f) { - // Lake water โ€” teal + // Lake water - teal float t = glm::clamp(lakeMask, 0.0f, 1.0f); r = (uint8_t)(20 + (1.0f - t) * 20); g = (uint8_t)(170 - t * 50); @@ -319,7 +319,7 @@ void TerrainDebugWindow::render(TerrainGenerationParams& params) { ImGui::SetNextItemWidth(200.0f); if (ImGui::SliderInt("View range (chunks)", &viewRangeChunks, 10, 2000)) navChanged = true; - // Step buttons โ€” jump by a quarter of the view range + // Step buttons - jump by a quarter of the view range const int step = std::max(1, viewRangeChunks / 4); if (ImGui::Button("W<<")) { camX -= step * 4 * 16; navChanged = true; } ImGui::SameLine(); if (ImGui::Button("W<")) { camX -= step * 16; navChanged = true; } ImGui::SameLine(); @@ -329,7 +329,7 @@ void TerrainDebugWindow::render(TerrainGenerationParams& params) { if (ImGui::Button("E>>")) { camX += step * 4 * 16; navChanged = true; } if (ImGui::Button("Reset view")) { camX = 0; camZ = 0; viewRangeChunks = 200; navChanged = true; } - // High-res toggle โ€” reallocates texture if changed + // High-res toggle - reallocates texture if changed bool newHighRes = highRes; if (ImGui::Checkbox("High Res (512x512, slower)", &newHighRes) && newHighRes != highRes) { highRes = newHighRes; diff --git a/src/client/TextureManager.cpp b/src/client/TextureManager.cpp index d013edd4..2e6a825d 100644 --- a/src/client/TextureManager.cpp +++ b/src/client/TextureManager.cpp @@ -206,7 +206,7 @@ bool TextureManager::loadResourcePack(const std::string& path, int textureSize) std::cout << "Loaded " << realTextureCount << " textures into array from: " << blockTextureDir << " and " << itemTextureDir << " (+1 missing-texture checker, " << layerCount << " base layers)" << std::endl; - // Return false when we couldn't find any real textures โ€” callers that want + // Return false when we couldn't find any real textures - callers that want // to abort or warn the user can still do so, while the renderer below // operates on the checker-only atlas without crashing. return hasAnyTexture; @@ -300,7 +300,7 @@ void TextureManager::setupBlockTextureMapping() { }; // โ”€โ”€ Tinted variants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - // Minecraft grass/leaves textures are grayscale โ€” the game multiplies + // Minecraft grass/leaves textures are grayscale - the game multiplies // them by a biome color at runtime. We do it once at load time. // Biome grass tints diff --git a/src/client/VegetationRenderer.cpp b/src/client/VegetationRenderer.cpp index fee5d0fe..fcb597bb 100644 --- a/src/client/VegetationRenderer.cpp +++ b/src/client/VegetationRenderer.cpp @@ -269,7 +269,7 @@ void VegetationRenderer::render() const { // Disable face culling so both sides of quads are visible glDisable(GL_CULL_FACE); - // No blending โ€” rely on discard in fragment shader for transparent pixels. + // No blending - rely on discard in fragment shader for transparent pixels. // Blending + depth writes causes transparent parts of the quad to occlude // terrain behind (see-through holes depending on draw order / angle). diff --git a/src/client/VideoPlayer.cpp b/src/client/VideoPlayer.cpp index ac3544f1..884ca894 100644 --- a/src/client/VideoPlayer.cpp +++ b/src/client/VideoPlayer.cpp @@ -169,7 +169,7 @@ // return true; // } -// // No more input available (EOF or read error) โ€” let caller handle seeking/looping. +// // No more input available (EOF or read error) - let caller handle seeking/looping. // return false; // } diff --git a/src/client/WaterFramebuffer.cpp b/src/client/WaterFramebuffer.cpp index f2ed417f..1fb62482 100644 --- a/src/client/WaterFramebuffer.cpp +++ b/src/client/WaterFramebuffer.cpp @@ -42,7 +42,7 @@ void WaterFramebuffer::setHDR(bool enabled) { hdrEnabled = enabled; // Rebuild both color attachments with the new internal format. Depth attachments - // don't depend on HDR but we tear down the whole FBO for simplicity โ€” this only + // don't depend on HDR but we tear down the whole FBO for simplicity - this only // runs when the user toggles the HDR setting, not per frame. destroyReflection(); destroyRefraction(); @@ -113,7 +113,7 @@ GLuint WaterFramebuffer::createTextureAttachment(int width, int height) { // In HDR mode the scene shader writes linear radiance that can exceed 1.0 // (dirLight ambient/diffuse boosts in Lighting::uploadLightingUniforms). // R11F_G11F_B10F gives us float headroom with the same bandwidth as RGB8 - // and no alpha channel cost โ€” the reflection/refraction passes don't use + // and no alpha channel cost - the reflection/refraction passes don't use // alpha. water.frag samples this texture and feeds the result into the // HDR scene buffer, which the final composite tonemaps once. const GLenum internalFmt = hdrEnabled ? GL_R11F_G11F_B10F : GL_RGB8; diff --git a/src/client/WaterRenderer.cpp b/src/client/WaterRenderer.cpp index 20f67184..486b6b3d 100644 --- a/src/client/WaterRenderer.cpp +++ b/src/client/WaterRenderer.cpp @@ -25,7 +25,7 @@ WaterRenderer::WaterRenderer(int screenWidth, int screenHeight) { fbos = std::make_unique(screenWidth, screenHeight); waterShader = std::make_unique("shaders/water.vert", "shaders/water.frag"); // Sky-reflection shader for water that isn't on the planar (sea-level) - // plane โ€” placed buckets, spread water, exposed deep-ocean side faces. + // plane - placed buckets, spread water, exposed deep-ocean side faces. placedWaterShader = std::make_unique("shaders/water_placed.vert", "shaders/water_placed.frag"); dudvTexture = waterShader->loadTexture("assets/textures/waterDudv.png"); waterNormalTexture = waterShader->loadTexture("assets/textures/normalMap.png"); @@ -68,7 +68,7 @@ void WaterRenderer::setDependencies(const std::shared_ptr &lightingRef } void WaterRenderer::advanceWaveTime(float dt) { - // Wrap at 2ฯ€ * 1024 โ€” large enough that the wrap is invisible (cos is + // Wrap at 2ฯ€ * 1024 - large enough that the wrap is invisible (cos is // periodic in 2ฯ€), small enough that float precision stays good. constexpr float kTwoPi = 6.28318530717958647692f; constexpr float kWrap = kTwoPi * 1024.0f; @@ -81,7 +81,7 @@ void WaterRenderer::setRefractionResolutionScale(float scale, int displayWidth, if (scale > 1.0f) scale = 1.0f; refractionResolutionScale = scale; - // Recreate the refraction FBO at the new size โ€” one-shot, not per frame. + // Recreate the refraction FBO at the new size - one-shot, not per frame. const int w = static_cast(static_cast(displayWidth) * scale); const int h = static_cast(static_cast(displayHeight) * scale); fbos->resizeRefraction(w, h); @@ -135,7 +135,7 @@ void WaterRenderer::renderWaterReflectionPass(const std::shared_ptr &sce lighting->uploadLightingUniforms(*sceneShader, reflectCamPosD, reflectedDir); // Skip uploadCSMUniforms: it binds csmDepthMaps which was just written by the shadow pass - // milliseconds ago โ€” binding it for reading here causes an implicit driver sync stall. + // milliseconds ago - binding it for reading here causes an implicit driver sync stall. sceneShader->setInt("ssaoEnabled", 0); sceneShader->setFloat("shadows.enabled", 0.0f); // Render reflection scene @@ -156,7 +156,7 @@ void WaterRenderer::renderWaterReflectionPass(const std::shared_ptr &sce reflectViewRot[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); renderer->updateFrustum(projection * reflectViewRot, reflectCamPosD); - // Optionally cap the per-chunk render distance for reflection only โ€” + // Optionally cap the per-chunk render distance for reflection only - // distant terrain rarely contributes meaningfully to a reflection but // costs the same draw-call/vertex work as the main pass. const float prevDistCap = renderer->getMaxRenderDistanceOverride(); @@ -166,7 +166,7 @@ void WaterRenderer::renderWaterReflectionPass(const std::shared_ptr &sce renderer->setMaxRenderDistanceOverride(prevDistCap); } // When reflection is disabled we still ran drawSky() above so the FBO - // contains a usable sky-tinted image โ€” water surface will sample it as + // contains a usable sky-tinted image - water surface will sample it as // a plain reflection of the sky, which is cheap and looks fine. glDisable(GL_CLIP_DISTANCE0); @@ -196,7 +196,7 @@ void WaterRenderer::renderWaterRefractionPass(const std::shared_ptr& sce // Render refraction scene lighting->uploadLightingUniforms(*sceneShader, camera->getEyePosD(), camera->getPlayer()->getCameraDir()); - // Skip uploadCSMUniforms: same shadow texture hazard as reflection โ€” and underwater + // Skip uploadCSMUniforms: same shadow texture hazard as reflection - and underwater // fragments don't need shadow computation at all. sceneShader->setInt("ssaoEnabled", 0); sceneShader->setFloat("shadows.enabled", 0.0f); @@ -204,7 +204,7 @@ void WaterRenderer::renderWaterRefractionPass(const std::shared_ptr& sce // them here would re-introduce caustics on terrain the sun can't reach sceneShader->setFloat("causticsEnabled", 0.0f); texMgr.bind(GL_TEXTURE0); - // Sea vegetation in refraction is expensive in dense biomes โ€” toggleable. + // Sea vegetation in refraction is expensive in dense biomes - toggleable. if (refractionRendersVegetation) renderer->updateVegetationUniforms(view, projection, clipPlane, glm::vec3(camera->getEyePosD())); renderer->render(sceneShader, view, camera->getEyePosD(), refractionRendersVegetation); @@ -226,7 +226,7 @@ void WaterRenderer::setupSurfaceShader(Shader& shader, // Y is also anchored: side faces of placed-water blocks use Y for V, // and without this the texture would translate vertically as the eye // moves up/down (since cameraRelPos.y = worldY - eye.y). The ocean - // shader only uses XZ and ignores the Y component โ€” uniform is a + // shader only uses XZ and ignores the Y component - uniform is a // silent no-op there. const double period = (dudvTiling > 0.0f) ? (1.0 / static_cast(dudvTiling)) : 1.0; const double anchorX = std::floor(eyePosD.x / period) * period; @@ -240,7 +240,7 @@ void WaterRenderer::setupSurfaceShader(Shader& shader, shader.setMat4("projection", projection); shader.setMat4("viewRot", viewRot); // Sun direction (toward-sun convention, matching dirLight). Set - // explicitly โ€” uploadFogUniforms only writes sunDir when fog is on. + // explicitly - uploadFogUniforms only writes sunDir when fog is on. shader.setVec3("sunDir", sunDir); shader.setVec3("lightColor", lighting->getDirectionalDiffuseColor()); // Sun-elevation fade band for specular (sunDir.y in [0.235, 0.315] diff --git a/src/client/blockRenderingHelperFunctions.cpp b/src/client/blockRenderingHelperFunctions.cpp index 75edb2f0..56d5d23b 100644 --- a/src/client/blockRenderingHelperFunctions.cpp +++ b/src/client/blockRenderingHelperFunctions.cpp @@ -160,7 +160,7 @@ void buildItemBillboard( const double lenSq = toCam.x * toCam.x + toCam.z * toCam.z; glm::dvec3 rightD; if (lenSq < 1e-9) { - // Item is directly above/below the eye โ€” pick an arbitrary right. + // Item is directly above/below the eye - pick an arbitrary right. rightD = glm::dvec3(1.0, 0.0, 0.0); } else { toCam /= std::sqrt(lenSq); diff --git a/src/client/characters/Character.cpp b/src/client/characters/Character.cpp index 5d122d2d..18334c29 100644 --- a/src/client/characters/Character.cpp +++ b/src/client/characters/Character.cpp @@ -233,7 +233,7 @@ void Character::swingArmAnimation(float deltaTime) { characterBodyParts.onArmSwingAnimation = false; characterBodyParts.armSwingPhase = 0.0f; - // Reset the right arm/forearm to rest โ€” walking animation will take over if needed. + // Reset the right arm/forearm to rest - walking animation will take over if needed. characterBodyParts.rightArm->rotation = glm::mat4(1.0f); characterBodyParts.rightForearm->rotation = glm::mat4(1.0f); return; @@ -244,7 +244,7 @@ void Character::swingArmAnimation(float deltaTime) float curve = sin(t * M_PI); // 0 โ†’ 1 โ†’ 0 // Arm rotates forward (bringing the forearm down in front of the body) and the - // forearm bends a bit extra โ€” mimics a simple overhead-ish punch/break motion. + // forearm bends a bit extra - mimics a simple overhead-ish punch/break motion. float shoulderAngle = curve * 1.6f; // swing forward/down float elbowAngle = curve * 0.6f; // slight forearm bend diff --git a/src/client/characters/ClientCreeper.cpp b/src/client/characters/ClientCreeper.cpp index f81b9a1a..e2945bdb 100644 --- a/src/client/characters/ClientCreeper.cpp +++ b/src/client/characters/ClientCreeper.cpp @@ -35,7 +35,7 @@ void ClientCreeper::setPartsDimensions() armScaleX = armScaleY = armScaleZ = 0.0f; armTransZ = armTransY = 0.0f; - // Four small square-cross-section legs โ€” one at each torso corner, outside the body. + // Four small square-cross-section legs - one at each torso corner, outside the body. legScaleX = 6.0f; legScaleY = 6.0f; legScaleZ = 6.0f; @@ -85,7 +85,7 @@ void ClientCreeper::createCharacterAt(const glm::vec3 &pos, float width, float h character.addChild(head); // Four legs at the torso corners. Translation values are expressed in leg-local - // units (Space composes as scale-then-translate internally โ€” see Character.cpp for + // units (Space composes as scale-then-translate internally - see Character.cpp for // the identical pattern on zombie legs). auto makeLeg = [&](float txLocal, float tzLocal) { auto leg = std::make_shared(glm::vec3(0.18f, 0.6f, 0.18f)); diff --git a/src/client/characters/LivingEntitiesManager.cpp b/src/client/characters/LivingEntitiesManager.cpp index c2b9f576..b58709d5 100644 --- a/src/client/characters/LivingEntitiesManager.cpp +++ b/src/client/characters/LivingEntitiesManager.cpp @@ -8,7 +8,7 @@ LivingEntitiesManager::LivingEntitiesManager() : characterShader("shaders/charac //builds the meshes for the cube (body parts) createCube(); - // Load entity skins. Missing files fall through โ€” manager::get returns 0 + // Load entity skins. Missing files fall through - manager::get returns 0 // and we render with per-limb colors as a fallback. skinManager.load("player", "assets/skins/steve.png"); skinManager.load("creeper", "assets/skins/creeper.png"); diff --git a/src/client/characters/cube.cpp b/src/client/characters/cube.cpp index ddba8994..581b6bde 100644 --- a/src/client/characters/cube.cpp +++ b/src/client/characters/cube.cpp @@ -23,37 +23,37 @@ void createCube() if (cubeVAO != 0) return; static const float vertices[] = { - // +X face (front) โ€” faceIndex 0 โ€” CCW from outside (+X) + // +X face (front) - faceIndex 0 - CCW from outside (+X) +0.5f, -0.5f, +0.5f, 0.0f, 1.0f, 1.0f, +0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, +0.5f, +0.5f, -0.5f, 0.0f, 0.0f, 0.0f, +0.5f, +0.5f, +0.5f, 0.0f, 1.0f, 0.0f, - // -X face (back) โ€” faceIndex 1 + // -X face (back) - faceIndex 1 -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, -0.5f, -0.5f, +0.5f, 1.0f, 0.0f, 1.0f, -0.5f, +0.5f, +0.5f, 1.0f, 0.0f, 0.0f, -0.5f, +0.5f, -0.5f, 1.0f, 1.0f, 0.0f, - // +Y face (top) โ€” faceIndex 2 + // +Y face (top) - faceIndex 2 -0.5f, +0.5f, +0.5f, 2.0f, 0.0f, 0.0f, +0.5f, +0.5f, +0.5f, 2.0f, 0.0f, 1.0f, +0.5f, +0.5f, -0.5f, 2.0f, 1.0f, 1.0f, -0.5f, +0.5f, -0.5f, 2.0f, 1.0f, 0.0f, - // -Y face (bottom) โ€” faceIndex 3 (V-flipped relative to top) + // -Y face (bottom) - faceIndex 3 (V-flipped relative to top) -0.5f, -0.5f, -0.5f, 3.0f, 1.0f, 1.0f, +0.5f, -0.5f, -0.5f, 3.0f, 1.0f, 0.0f, +0.5f, -0.5f, +0.5f, 3.0f, 0.0f, 0.0f, -0.5f, -0.5f, +0.5f, 3.0f, 0.0f, 1.0f, - // -Z face (character right) โ€” faceIndex 4 + // -Z face (character right) - faceIndex 4 -0.5f, +0.5f, -0.5f, 4.0f, 0.0f, 0.0f, +0.5f, +0.5f, -0.5f, 4.0f, 1.0f, 0.0f, +0.5f, -0.5f, -0.5f, 4.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 4.0f, 0.0f, 1.0f, - // +Z face (character left) โ€” faceIndex 5 + // +Z face (character left) - faceIndex 5 -0.5f, -0.5f, +0.5f, 5.0f, 1.0f, 1.0f, +0.5f, -0.5f, +0.5f, 5.0f, 0.0f, 1.0f, +0.5f, +0.5f, +0.5f, 5.0f, 0.0f, 0.0f, @@ -90,11 +90,11 @@ void createCube() glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0); - // aFaceIndex (location 1) โ€” stored as float, cast to int in shader + // aFaceIndex (location 1) - stored as float, cast to int in shader glEnableVertexAttribArray(1); glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float))); - // aFaceCorner (location 2) โ€” skin-auth UV corner in [0,1]^2 + // aFaceCorner (location 2) - skin-auth UV corner in [0,1]^2 glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(4 * sizeof(float))); diff --git a/src/client/items/ItemPropEntity.cpp b/src/client/items/ItemPropEntity.cpp index c724e74d..a4e0a66b 100644 --- a/src/client/items/ItemPropEntity.cpp +++ b/src/client/items/ItemPropEntity.cpp @@ -22,7 +22,7 @@ void ItemPropEntity::createMesh(std::vector &meshVertices, const glm::dve const float rz = static_cast(relD.z); // Torches drop as a billboard sprite (like misc items / vanilla drops), - // not a cube โ€” the cube would tile the whole torch image on each face. + // not a cube - the cube would tile the whole torch image on each face. if (auto* tb = std::get_if(&type); tb && isTorch(*tb)) { const int layer = texMgr ? texMgr->getItemSpriteLayer(type) : 0; buildItemBillboard(meshVertices, relD, layer, skyFactor, blockFactor); @@ -31,7 +31,7 @@ void ItemPropEntity::createMesh(std::vector &meshVertices, const glm::dve if (isItemFlat(type)) { const int layer = texMgr ? texMgr->getItemSpriteLayer(type) : 0; - // Vegetation is rooted in the world โ€” render as a stationary X-cross + // Vegetation is rooted in the world - render as a stationary X-cross // matching how plants are drawn in chunks. Tools / ingots / misc // items have no fixed orientation, so they billboard around Y like // vanilla Minecraft drops. diff --git a/src/client/items/ItemPropEntityManager.cpp b/src/client/items/ItemPropEntityManager.cpp index 8695f62f..2051d54d 100644 --- a/src/client/items/ItemPropEntityManager.cpp +++ b/src/client/items/ItemPropEntityManager.cpp @@ -60,7 +60,7 @@ size_t ItemPropEntityManager::updateMesh(std::vector // Sample the world's sky-light grid at the item's drop position so it // darkens in caves the way terrain does. Falls back to fully sunlit - // (1.0) when the chunk isn't loaded โ€” same default getSkyLightWorld + // (1.0) when the chunk isn't loaded - same default getSkyLightWorld // returns and what Chunk::getSkyLight uses for not-yet-computed grids. float skyFactor = 1.0f; float blockFactor = 0.0f; @@ -165,14 +165,14 @@ void ItemPropEntityManager::draw(const glm::mat4 &projection, const glm::mat4 &v shader->setMat4("projection", projection); // Note: written as "viewRot" (translation-free) to match the name - // Lighting::uploadCSMUniforms sets โ€” that call also writes "view" (with + // Lighting::uploadCSMUniforms sets - that call also writes "view" (with // translation) which the CSM lookup uses, so they don't collide. shader->setMat4("viewRot", viewRot); // Sprite-style drops (vegetation, weapons, misc) are emitted as a cross // of two flat quads; disable backface culling so they're visible from // every angle. - // Draw only the slots updateMesh actually wrote โ€” non-drawable entities + // Draw only the slots updateMesh actually wrote - non-drawable entities // are skipped during compaction, so issuing entities.size() vertices would // waste CPU/GPU work emitting zeroed/padded triangles for them. glDisable(GL_CULL_FACE); diff --git a/src/client/menus/InventoryUI.cpp b/src/client/menus/InventoryUI.cpp index d0f54fa3..c8c26848 100644 --- a/src/client/menus/InventoryUI.cpp +++ b/src/client/menus/InventoryUI.cpp @@ -438,7 +438,7 @@ void InventoryUI::drawDeathScreen(float health) const float bandH = fullscreenHeight * 0.18f; for (int i = 0; i < 4; ++i) { - const float t = (i + 1) / 4.0f; // 0.25..1.0 โ€” outer bands are darker + const float t = (i + 1) / 4.0f; // 0.25..1.0 - outer bands are darker const float a = 0.18f * t * fade; drawSimpleQuad(0, fullscreenHeight - bandH * (i + 1), fullscreenWidth, bandH, glm::vec4(0.0f, 0.0f, 0.0f, a)); diff --git a/src/client/menus/MainMenu.cpp b/src/client/menus/MainMenu.cpp index 86ea19b4..03dbe8c1 100644 --- a/src/client/menus/MainMenu.cpp +++ b/src/client/menus/MainMenu.cpp @@ -156,7 +156,7 @@ void MainMenu::onRender() textRenderer.setScale(smallScale); textRenderer.setProjection(fullscreenWidth, fullscreenHeight); - textRenderer.renderText("pre-pre-pre-alpha", 10.0f * menuScale, 10.0f * menuScale, glm::vec3(0.7f)); + textRenderer.renderText("alpha 1.0", 10.0f * menuScale, 10.0f * menuScale, glm::vec3(0.7f)); // Credits (bottom-right) std::string credits = "Created by ldominiq & lskraber"; diff --git a/src/server/ChunkGeneration.cpp b/src/server/ChunkGeneration.cpp index dc614fd5..ee2be2f8 100644 --- a/src/server/ChunkGeneration.cpp +++ b/src/server/ChunkGeneration.cpp @@ -499,7 +499,7 @@ void ChunkGeneration::placeTree(BlockStorage &blocks, int trunkWorldX, int trunk // -------------------- Canopy variants -------------------- auto placeRoundCanopy = [&]() { - // Oak / Birch / Dark Oak โ€” round pyramid with organic ragged edges. + // Oak / Birch / Dark Oak - round pyramid with organic ragged edges. constexpr int leafRadii[4] = {2, 2, 1, 0}; for (int layer = 0; layer < 4; ++layer) placeLeafLayer(canopyCX, canopyCZ, surfaceY + treeHeight - 2 + layer, @@ -726,7 +726,7 @@ void ChunkGeneration::generateTrees(BlockStorage &blocks, const TerrainGeneratio const BiomeType biome = biomeForColumn(worldX, worldZ, surfaceY, localTrunkX, localTrunkZ); - // One chance roll per column โ€” every biome consumes this roll + // One chance roll per column - every biome consumes this roll // up front so cross-biome reproducibility is preserved. const int chanceRoll = static_cast(rng() % 1000); const TreeSpec spec = rollTreeSpec(biome, chanceRoll, rng); @@ -1244,18 +1244,18 @@ BiomeType ChunkGeneration::computeBiome(const TerrainGenerationParams& terrainPa return BiomeType::TUNDRA; } - // Nether โ€” hot, arid, elevated terrain (high or peak peaks) + // Nether - hot, arid, elevated terrain (high or peak peaks) if (ct == ClimateTemperature::HOT && ch == ClimateHumidity::ARID && cpv >= ClimatePeaksValleys::HIGH) return BiomeType::NETHER; - // Volcanic โ€” hot, arid, flat-to-mid terrain (elevated Nether already claimed above) + // Volcanic - hot, arid, flat-to-mid terrain (elevated Nether already claimed above) if (ct == ClimateTemperature::HOT && ch == ClimateHumidity::ARID) return BiomeType::VOLCANIC; - // Mesa โ€” hot, dry/arid-but-not-arid (ARID is claimed by VOLCANIC above), or + // Mesa - hot, dry/arid-but-not-arid (ARID is claimed by VOLCANIC above), or // warm/hot + dry + not too eroded if ((ct == ClimateTemperature::WARM || ct == ClimateTemperature::HOT) && ch <= ClimateHumidity::DRY && @@ -1266,45 +1266,45 @@ BiomeType ChunkGeneration::computeBiome(const TerrainGenerationParams& terrainPa if (ct == ClimateTemperature::HOT && ch == ClimateHumidity::DRY) return BiomeType::MESA; - // Red Desert โ€” warm + arid flat lands (distinct from hot MESA) + // Red Desert - warm + arid flat lands (distinct from hot MESA) if (ct == ClimateTemperature::WARM && ch == ClimateHumidity::ARID && ce >= ClimateErosion::E4) return BiomeType::RED_DESERT; - // Desert โ€” warm/hot, arid/dry only (NEUTRAL excluded so Savanna can claim WARM+NEUTRAL) + // Desert - warm/hot, arid/dry only (NEUTRAL excluded so Savanna can claim WARM+NEUTRAL) if ((ct == ClimateTemperature::WARM || ct == ClimateTemperature::HOT) && ch <= ClimateHumidity::DRY && height < 110) return BiomeType::DESERT; - // Savanna โ€” warm, moderate (checked before Jungle/Swamp to avoid being swallowed) + // Savanna - warm, moderate (checked before Jungle/Swamp to avoid being swallowed) if (ct == ClimateTemperature::WARM && ch == ClimateHumidity::NEUTRAL && cc >= ClimateContinentalness::MID_INLAND && cpv <= ClimatePeaksValleys::MID) return BiomeType::SAVANNA; - // Jungle โ€” hot and wet + // Jungle - hot and wet if ((ct == ClimateTemperature::HOT && ch >= ClimateHumidity::HUMID) || (ct == ClimateTemperature::WARM && ch == ClimateHumidity::WET)) return BiomeType::JUNGLE; - // Swamp โ€” temperate/warm, wet, flat/valley + // Swamp - temperate/warm, wet, flat/valley if ((ct == ClimateTemperature::TEMPERATE || ct == ClimateTemperature::WARM) && ch >= ClimateHumidity::HUMID && cpv <= ClimatePeaksValleys::LOW && cc <= ClimateContinentalness::NEAR_INLAND) return BiomeType::SWAMP; - // Dark Forest โ€” cool/temperate, humid + // Dark Forest - cool/temperate, humid if (ct <= ClimateTemperature::TEMPERATE && ch >= ClimateHumidity::HUMID) return BiomeType::DARK_FOREST; - // Mountain โ€” high peaks, inland (checked before Birch Forest so mountainous + // Mountain - high peaks, inland (checked before Birch Forest so mountainous // temperate+neutral terrain becomes mountains, not forest) if (cpv >= ClimatePeaksValleys::HIGH && cc == ClimateContinentalness::FAR_INLAND && ch <= ClimateHumidity::NEUTRAL) return BiomeType::MOUNTAIN; - // Birch Forest โ€” temperate, neutral humidity, low/mid terrain + // Birch Forest - temperate, neutral humidity, low/mid terrain if (ct == ClimateTemperature::TEMPERATE && (ch == ClimateHumidity::DRY)) return BiomeType::BIRCH_FOREST; @@ -1330,7 +1330,7 @@ BiomeType ChunkGeneration::computeBiome(const TerrainGenerationParams& terrainPa // float pv = getPV(terrainParams, worldX, worldZ); // float aridity = (1.0f - humidCoarse) * tempCoarse; - // // MESA: hot + very dry โ€” terracotta terrain + // // MESA: hot + very dry - terracotta terrain // if (tempCoarse > 0.60f && humidCoarse < 0.35f && aridity > 0.25f) // return BiomeType::MESA; @@ -1504,7 +1504,7 @@ void ChunkGeneration::generateVegetation(const BlockStorage &blocks, const Terra }; std::mt19937 rng(seedData); - // Skip some columns for variety โ€” spawn chance is per-biome + // Skip some columns for variety - spawn chance is per-biome int spawnChance; // out of 100 switch (biome) { case BiomeType::PLAINS: spawnChance = 10; break; @@ -1704,7 +1704,7 @@ void ChunkGeneration::generateVegetation(const BlockStorage &blocks, const Terra vegetation.push_back(veg); } } - // Don't store in block grid โ€” keep water blocks intact + // Don't store in block grid - keep water blocks intact } else { // Land vegetation: stored only in the block grid. // buildVegetationMesh() scans blocks to derive instances for rendering. diff --git a/src/server/Server.cpp b/src/server/Server.cpp index 432ec717..c1dfe8dd 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -451,7 +451,7 @@ void Server::sendEntitiesSnapshotTo(const sockaddr_in &cliaddr) if (!entity || entity.get() == selfEntity) continue; // Mirror sendEntitiesPositionDeltas's packet layout exactly. Any - // field added there needs to land here too โ€” keep the two in sync. + // field added there needs to land here too - keep the two in sync. NetEntityMove pkt; pkt.eEntityType = entity->getEntityType(); pkt.entityID = entity->getID(); @@ -600,7 +600,7 @@ void Server::receivePlayerInputs(NetPlayerInputs &pkt, const sockaddr_in &cliadd // Resolve the player's currently-held item id and flag a broadcast if it // changed. Re-checking on every input packet also catches inventory - // mutations (drops, pickups, swaps) that don't touch the hotbar index โ€” + // mutations (drops, pickups, swaps) that don't touch the hotbar index - // they'd otherwise need their own dirty flag to reach NetEntityMove. { uint16_t newHeldType = player->movement->inventory->getActiveItemID(); @@ -1100,7 +1100,7 @@ void Server::sendDeaths() if (ent->diedByExplosion && ent->getLivingEntityType() != PLAYER) { - // No body left โ€” creepers that self-detonate vanish immediately. + // No body left - creepers that self-detonate vanish immediately. le = world->livingEntities.erase(le); continue; } @@ -1180,7 +1180,7 @@ void Server::sendChunk(CPlayerInfo &player) sendPacketTo(CH, player.addr); // 3. Split into packets. Each CHUNK_DATA is Reliable, so the layer - // guarantees in-order delivery โ€” no per-fragment sequence needed. + // guarantees in-order delivery - no per-fragment sequence needed. // Account for packet encoding overhead: 1(type)+4(seq)+1(flags)+4(X)+4(Z)+4(len) = 18 bytes size_t payloadCapacity = MAXLINE - 18; @@ -1349,7 +1349,7 @@ void Server::sendNewGroupPacketTo(std::vector& pkts, const sockaddr_i // Groups carry state that's always reliable-worthy today (modified blocks, // connect handshake batches). Mark the outer envelope reliable so the // whole batch is delivered in order. Inner packets are unpacked after - // ingest and bypass the reliability layer โ€” their own flags are ignored. + // ingest and bypass the reliability layer - their own flags are ignored. NetPacketGroup group; group.flags = group.flags | PacketFlags::Reliable; int currSize = 8; // header (6) + u16 group count (2) diff --git a/src/server/World.cpp b/src/server/World.cpp index c5b7553b..50f50596 100644 --- a/src/server/World.cpp +++ b/src/server/World.cpp @@ -104,7 +104,7 @@ void World::dumpHeightmap(const TerrainGenerationParams& params, int centerChunk imgLakeNoise.resize(npixels); imgLakeMask.resize(npixels); } - // Precompute erosion spline range once โ€” used in every pixel + // Precompute erosion spline range once - used in every pixel float eroMin = std::numeric_limits::infinity(); float eroMax = -std::numeric_limits::infinity(); for (const auto& sp : erosionSpline) { @@ -1327,7 +1327,7 @@ void World::trySpawnNightMobs(const std::vector &players) return; // Night-time check: sun elevation is cos(skyTimeOffset * 0.1) (see Lighting.cpp). - // Negative elevation means the sun is below the horizon โ€” i.e. night. + // Negative elevation means the sun is below the horizon - i.e. night. // Using this formulation avoids wrap-around issues as skyTimeOffset accumulates. // Surface spawning is gated on night; cave spawning runs regardless so mining // stays hazardous during the day too. @@ -1341,7 +1341,7 @@ void World::trySpawnNightMobs(const std::vector &players) constexpr int SCAN_TOP_Y = 200; constexpr int SCAN_BOTTOM_Y = 4; - // Cave spawning parameters โ€” closer than surface spawns so mobs actually + // Cave spawning parameters - closer than surface spawns so mobs actually // show up near a mining player, and biased to Y bands around the player. constexpr int CAVE_MIN_DIST = 16; constexpr int CAVE_MAX_DIST = 48; @@ -1427,7 +1427,7 @@ void World::trySpawnNightMobs(const std::vector &players) if (yHi - yLo < 2) return false; // Scan downward from a random Y in the band looking for an air pocket - // (2+ air blocks) sitting on a solid floor โ€” somewhere a mob can stand. + // (2+ air blocks) sitting on a solid floor - somewhere a mob can stand. int startY = std::uniform_int_distribution(yLo, yHi)(spawnRng); bool airAbove1 = isAir(startY + 2); bool airAbove2 = isAir(startY + 1); diff --git a/src/shared/Chunk.cpp b/src/shared/Chunk.cpp index ce2bcf4e..15acb179 100644 --- a/src/shared/Chunk.cpp +++ b/src/shared/Chunk.cpp @@ -108,13 +108,13 @@ bool Chunk::isBlockVisible(glm::ivec3 pos) { // // HOW IT WORKS (Minecraft-style BFS flood-fill): // -// 1) SEEDING PHASE โ€” For every (x, z) column in the chunk, we walk +// 1) SEEDING PHASE - For every (x, z) column in the chunk, we walk // downward from y=HEIGHT-1. As long as the block is transparent // (air / water / leaves), it gets light level 15 (full sunlight) // and is pushed into a BFS queue. The moment we hit a solid block, -// we stop โ€” sunlight doesn't penetrate straight through stone. +// we stop - sunlight doesn't penetrate straight through stone. // -// 2) SPREADING PHASE โ€” Classic BFS. For each block in the queue we +// 2) SPREADING PHASE - Classic BFS. For each block in the queue we // try all 6 neighbors (ยฑx, ยฑy, ยฑz). If the neighbor is transparent // and its current light < (our light - 1), we update it and push it. // This means light "leaks" sideways into caves through openings, @@ -134,7 +134,7 @@ uint8_t Chunk::getSkyLight(int x, int y, int z) const { if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT || z < 0 || z >= DEPTH) return 0; if (skyLight.empty()) - return 15; // Not computed yet โ€” assume full sunlight. + return 15; // Not computed yet - assume full sunlight. // This is the correct default for the common case // (surface blocks). When concurrent chunk builds // read a neighbor that hasn't been built yet, the @@ -153,11 +153,11 @@ void Chunk::computeSkyLight() { // filled array and read incorrect values. By keeping the old // array in place until the new one is ready, concurrent readers // always see either the previous fully-computed result or the - // new one โ€” never a half-baked intermediate state. + // new one - never a half-baked intermediate state. std::vector localSkyLight(BLOCK_COUNT, 0); // We'll use a queue of (x, y, z) positions to flood-fill light. - // "struct" to keep it readable โ€” each entry is a block to process. + // "struct" to keep it readable - each entry is a block to process. struct LightNode { int16_t x, y, z; }; @@ -168,7 +168,7 @@ void Chunk::computeSkyLight() { // assign light=15 (direct sunlight) and enqueue for BFS spreading. // // Why enqueue every sunlit block? Because a sunlit block could be - // next to a cliff face where the terrain is taller โ€” its horizontal + // next to a cliff face where the terrain is taller - its horizontal // neighbor might be a dark air block inside the ground that needs // light. The BFS loop below will quickly skip interior blocks // (all their neighbors are already at 15), so this is efficient. @@ -215,7 +215,7 @@ void Chunk::computeSkyLight() { int neighborZ = current.z + dz[dir]; // Stay within chunk bounds (we don't cross chunk borders - // for now โ€” that would require the neighbors to be loaded + // for now - that would require the neighbors to be loaded // and would complicate threading; this is good enough for // visible cave darkening within a chunk). if (neighborX < 0 || neighborX >= WIDTH || @@ -240,7 +240,7 @@ void Chunk::computeSkyLight() { // Publish the fully-computed array. std::swap is fast (just // swaps internal pointers) and makes the transition atomic from - // the perspective of any concurrent reader โ€” they either see the + // the perspective of any concurrent reader - they either see the // old empty vector (fallback to 15, see getSkyLight()) or the // fully-computed one. std::swap(skyLight, localSkyLight); @@ -250,7 +250,7 @@ uint8_t Chunk::getBlockLight(int x, int y, int z) const { if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT || z < 0 || z >= DEPTH) return 0; if (blockLight.empty()) - return 0; // Not computed yet / no emitters โ€” fully dark. + return 0; // Not computed yet / no emitters - fully dark. return blockLight[x + WIDTH * (y + HEIGHT * z)]; } @@ -261,7 +261,7 @@ uint8_t Chunk::getBlockLight(int x, int y, int z) const { // on a neighbour's computed light) there is no cross-chunk feedback: placing // lights correctly across seams/diagonals, and breaking clears immediately. // The expensive cross-chunk scan is skipped entirely when no torch is in or -// next to this chunk (the common case โ€” generated terrain has none). +// next to this chunk (the common case - generated terrain has none). void Chunk::computeBlockLight() { static constexpr int MARGIN = 14; // max torch travel (14 โ†’ 0) static constexpr int EW = WIDTH + 2 * MARGIN; @@ -331,12 +331,12 @@ void Chunk::computeBlockLight() { } if (!containsTorch && !neighborTorch) { - std::swap(blockLight, localBlockLight); // nothing emits โ€” all dark + std::swap(blockLight, localBlockLight); // nothing emits - all dark return; } // Cross-chunk path. Seeds are collected by scanning ONLY the chunks that - // actually contain a torch (containsTorch) in their own local coords โ€” no + // actually contain a torch (containsTorch) in their own local coords - no // per-cell weak_ptr locking. Empty neighbours (the vast majority) cost // nothing. We also track the torch Y-range so the BFS volume can be // clamped to [minY-MARGIN, maxY+MARGIN] instead of the full 256 columns: @@ -583,7 +583,7 @@ void Chunk::saveToStream(std::ostream& out) const { // Save block data blockIndices.saveToStream(out); - // Biome map โ€” serialised as fixed-width uint8_t, independent of BiomeType's in-memory size + // Biome map - serialised as fixed-width uint8_t, independent of BiomeType's in-memory size for (const auto& b : biomeMap) { uint8_t v = static_cast(b); out.write(reinterpret_cast(&v), sizeof(v)); @@ -664,7 +664,7 @@ void Chunk::loadFromStream(std::istream& in) { vegetation.push_back(veg); - // Don't overwrite water blocks with sea vegetation โ€” + // Don't overwrite water blocks with sea vegetation - // sea vegetation is rendered purely via the vegetation renderer if (!isSeaVegetation(veg.type)) { setBlock(veg.x, veg.y, veg.z, veg.type); diff --git a/src/shared/Entity.cpp b/src/shared/Entity.cpp index 0f40dac0..7a9c451f 100644 --- a/src/shared/Entity.cpp +++ b/src/shared/Entity.cpp @@ -29,7 +29,7 @@ AABB Entity::constructAABB(const glm::dvec3 &pos) { }; bool Entity::aabbCollidesWithWorld(const AABB &box, const ICommonWorld &world) { - // compute block search bounds (floor in double โ€” at 5M, float floor of + // compute block search bounds (floor in double - at 5M, float floor of // min.x + EPS would land on the wrong integer because the LSB is ~0.5m). int minX = (int)std::floor(box.min.x + EPS); int maxX = (int)std::floor(box.max.x - EPS); diff --git a/src/shared/Mobs/PlayerMovement.cpp b/src/shared/Mobs/PlayerMovement.cpp index 1fe111fc..843dd00d 100644 --- a/src/shared/Mobs/PlayerMovement.cpp +++ b/src/shared/Mobs/PlayerMovement.cpp @@ -322,7 +322,7 @@ void PlayerMovement::calculateNewPosition(const ICommonWorld &world) if (skipDuplicateInputs) { // Server path: drain the per-player input queue, running one physics step per // queued input. When the client sends N inputs in a single frame (low FPS - // catch-up), all N packets end up here and each gets its own step โ€” keeping + // catch-up), all N packets end up here and each gets its own step - keeping // server and client tick counts in sync instead of the server skipping to the // last input and being N-1 ticks behind. if (pendingInputs.empty())