|
@ -5,11 +5,19 @@ site/hugo
|
|||
site/hugo.exe
|
||||
|
||||
# Hugo generated static website files.
|
||||
build/
|
||||
public/
|
||||
site/public/
|
||||
.publish/
|
||||
|
||||
# Dynamic content imported on deploy.
|
||||
site/content/wiki/
|
||||
site/content/game/
|
||||
site/static/images/game/icons
|
||||
site/static/images/game/boxart
|
||||
!site/static/images/game/boxart/default.png
|
||||
site/static/images/screenshots0/
|
||||
site/static/savefiles/
|
||||
site/data/twitter.json
|
||||
|
||||
# Filesystem stuff.
|
||||
|
|
67
.travis.yml
|
@ -1,51 +1,30 @@
|
|||
# Build status located at https://travis-ci.org/citra-emu/citra-web
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "node"
|
||||
cache: yarn
|
||||
|
||||
node_js: "6"
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
before_script:
|
||||
- echo '========== Importing wiki articles into hugo =========='
|
||||
- cd ./scripts/wiki/
|
||||
script:
|
||||
- echo '========== Installing gulp & dependencies =========='
|
||||
- sudo apt-get install graphicsmagick
|
||||
- wget -O hugo.deb https://github.com/gohugoio/hugo/releases/download/v0.52/hugo_0.52_Linux-64bit.deb
|
||||
- sudo dpkg -i hugo.deb
|
||||
- yarn install
|
||||
- node app.js
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
- echo '========== Importing games wiki articles into hugo =========='
|
||||
- cd ./scripts/games/
|
||||
- yarn install
|
||||
- node app.js
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
- echo '========== Importing twitter tweets into hugo =========='
|
||||
- cd ./scripts/twitter/
|
||||
- yarn install
|
||||
- node app.js
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
- echo '========== Installing gulp / hugo dependencies =========='
|
||||
- yarn global add @alrra/travis-scripts
|
||||
- yarn global add gulp
|
||||
- yarn global add hugo-bin
|
||||
- hugo version
|
||||
|
||||
- echo '========== Configuring Github Pages =========='
|
||||
- git config --global user.email "citra+citrabotweb@citra-emu.org"
|
||||
- git config --global user.name "CitraBotWeb"
|
||||
- set-up-ssh --key "$encrypted_c7ee54b5843f_key" --iv "$encrypted_c7ee54b5843f_iv" --path-encrypted-key "bf215181b5140522137b3d4f6b73544a.enc"
|
||||
|
||||
- echo '========== Starting gulp deploy task =========='
|
||||
- gulp deploy
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
env:
|
||||
- HUGO_ENV=PRD
|
||||
|
||||
# set-up-ssh is provided by travis-scripts.
|
||||
# Setting up the SSH key for Github is described here.
|
||||
# https://github.com/alrra/travis-scripts/blob/master/doc/github-deploy-keys.md
|
||||
- hugo version
|
||||
- yarn run gulp all --production
|
||||
deploy:
|
||||
provider: pages
|
||||
skip_cleanup: true
|
||||
github_token: $GITHUB_TOKEN # Set in travis-ci.org dashboard
|
||||
local_dir: build
|
||||
repo: CitraBotWeb/CitraBotWeb.github.io
|
||||
target_branch: master
|
||||
fqdn: citra-emu.org
|
||||
on:
|
||||
branch: master
|
||||
notifications:
|
||||
email:
|
||||
- mods@citra-emu.org
|
||||
|
|
848
LICENSE
|
@ -1,281 +1,620 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
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
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
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.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
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.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
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.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
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.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
0. Definitions.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
"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.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
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) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
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.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
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.
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
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.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
1. Source Code.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
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.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
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.
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
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.
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
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.
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
2. Basic Permissions.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
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.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
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.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
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.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
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.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
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.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
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.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
14. Revised Versions of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
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.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
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.
|
||||
|
||||
NO WARRANTY
|
||||
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.
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
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
|
||||
|
||||
|
@ -287,53 +626,36 @@ free software which everyone can redistribute and change under these terms.
|
|||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
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.
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
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 General Public License for more details.
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
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.
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
|
22
README.md
|
@ -1 +1,23 @@
|
|||
# Citra Official Website
|
||||
|
||||
This repository contains the source for the [Citra Emulator](https://github.com/citra-emu/citra) website, which can be found at https://citra-emu.org/.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Required Dependencies
|
||||
- [Node.js](https://nodejs.org) `sudo apt-get install nodejs nodejs-legacy`
|
||||
- [Gulp.js](http://gulpjs.com) `sudo npm install -g gulp`
|
||||
- [Hugo](https://gohugo.io/) `sudo npm install -g hugo-bin`
|
||||
- [GraphicsMagick](http://www.graphicsmagick.org/) `sudo apt-get install graphicsmagick`
|
||||
- [ImageMagick](https://www.imagemagick.org) (Should be installed through `graphicsmagick`)
|
||||
|
||||
### Instructions
|
||||
1. Open up a terminal or command prompt in the `citra-web` directory.
|
||||
2. Run `npm install`.
|
||||
3. Run `gulp all`.
|
||||
|
||||
Now, Gulp should have built the Citra website, its external content, and hosted it locally.
|
||||
It will print out the `Access URL`s, which you can go to in your browser to view it.
|
||||
|
||||
## Sitemap
|
||||
The sitemap for the Citra website can be found in [SITEMAP.md](SITEMAP.md).
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
# Sitemap
|
||||
This file will give an overview of what each folder and file in this repository does. There are 2 parts to this document:
|
||||
- [Info](#info)
|
||||
- [Structure](#structure)
|
||||
|
||||
## Info
|
||||
|
||||
This section gives some background information that will be referred to in the [Structure](#structure) part of this document.
|
||||
|
||||
### Keys
|
||||
Some of the JSONs in this repositor use a field named `key`. The value of this should be the same as the name of the parent object. This should be lowercase, with no spaces.
|
||||
|
||||
### Names
|
||||
JSONs that have a `key` field (See: [Keys](#keys)) also have a `name` field. The value of this doesn't have to be the same as the value of `key` or the name of the parent object, and can have capitalization and spaces.
|
||||
|
||||
## Structure
|
||||
This section will describe the layout of this repository, and what each file and folder does.
|
||||
|
||||
### Site (`/site/`)
|
||||
The `site` folder is the root folder of the site.
|
||||
|
||||
#### Content (`/site/content/`)
|
||||
The `content` folder contains the [front matter](https://gohugo.io/content/front-matter/).
|
||||
|
||||
##### Main Pages Front Matter (`/site/content/*.md`)
|
||||
The `*.md` files are the front matter of the site. Documentation for the front matter can be found [here](https://gohugo.io/content/front-matter/). The [TOML](https://github.com/toml-lang/toml) fields used here are:
|
||||
- `title`
|
||||
- `advertisement`: Whether advertisements are displayed or not.
|
||||
|
||||
##### Blog Entries (`/site/content/entry/`)
|
||||
The `entry` folder contains the front matter for the blog.
|
||||
|
||||
###### Blog Entries Front Matter (`/site/content/entry/*.md`)
|
||||
The `*.md` files here are the front matter for the blog. Documentation for the front matter can be found [here](https://gohugo.io/content/front-matter/). The [TOML](https://github.com/toml-lang/toml) fields used here are:
|
||||
- `date`: The date that the article was written on, following [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), preferably down to the second. An example for Feburary 23, 2016, at 11:30 PM EST is `2016-02-23T23:30:00-05:00`.
|
||||
- `title`
|
||||
- `tags`
|
||||
- `author`: The name(s) of the person/people that wrote the article, in `/site/data/authors.json`.
|
||||
- `forum`: The ID of the forum topic for discussing the article.
|
||||
|
||||
#### Data (`/site/data/`)
|
||||
The `data` folder contains [JSON](http://www.json.org/) files with data.
|
||||
|
||||
##### Authors (`/site/data/authors.json`)
|
||||
The `authors.json` file has info about each of the blog authors. The [JSON](http://www.json.org/) fields used are:
|
||||
- User (Object): The data for a user.
|
||||
- `key` (String): The name of the user (See: [Keys](#keys)).
|
||||
- `name` (String): The name of the user (See: [Names](#names)).
|
||||
- `avatar` (String): The link to the user's avatar on the forums.
|
||||
|
||||
##### Compatability (`/site/data/compatibility.json`)
|
||||
The `compatibility.json` file has info about each of the compataibility ranks in the [Game Compatibility List](https://citra-emu.org/game/). The [JSON](http://www.json.org/) fields used here are:
|
||||
- Rating (Object): The data for a rating.
|
||||
- `key` (String): The number representing the rating (See: [Keys](#keys)).
|
||||
- `name` (String): The name of the rating.
|
||||
- `color` (String): The HTML color code for the rating, including the `#`.
|
||||
- `description` (String): A description of the rating.
|
||||
|
||||
##### Virtual Console Systems (`/site/data/vcSystems.json`)
|
||||
The `vcSystems.json` file has info about each of the 3DS's Virtual Consoles, used in the [Game Compatibility List](https://citra-emu.org/game/). The [JSON](http://www.json.org/) fields used here are:
|
||||
- Console (Object): The data for a rating.
|
||||
- `key` (String): The short name of a console (See: [Keys](#keys)).
|
||||
- `name` (String): The full name of the console (See: [Names](#names)).
|
||||
|
||||
##### Game Types (`/site/data/gameTypes.json`)
|
||||
The `gameTypes.json` file has info about each of the 3DS game types, used in the [Game Compatibility List](https://citra-emu.org/game/). The [JSON](http://www.json.org/) fields used here are:
|
||||
- Game Type (Object): The data for a game type.
|
||||
- `name` (String): The full name of the console (See: [Names](#names)).
|
||||
|
||||
#### Translations (`/site/i18n/`)
|
||||
The `i18n` folder is a placeholder for if the site is translated.
|
||||
|
||||
#### Images (`/site/static/images/`)
|
||||
The `images` folder, and its subfolders have PNG images used throughout the site.
|
||||
|
||||
#### Bootstrap Theme (`/site/themes/citra-bs-theme`)
|
||||
The `citra-bs-theme` folder describes what the final pages should look like.
|
||||
|
||||
##### Theme Layout (`/site/themes/citra-bs-theme/layout/`)
|
||||
The `layout` folder has the structure for the root directory of the final site that users will see.
|
||||
|
||||
###### HTML Templates (`/site/themes/citra-bs-theme/layout/*.html`)
|
||||
The `*.html` files has the HTML templates for the final page. Documentation for these files can be found [here](https://gohugo.io/templates/list).
|
||||
|
||||
###### RSS File (`/site/themes/citra-bs-theme/layout/rss.xml`)
|
||||
The `rss.xml` file has info for 3rd party RSS readers.
|
||||
|
||||
###### Sitemap (`/site/themes/citra-bs-theme/layout/sitemap.xml`)
|
||||
The `sitemap.xml` has a sitemap for search engines to index.
|
||||
|
||||
##### Theme Static Data (`/site/themes/citra-bs-theme/static/`)
|
||||
The `static` folder has resources that will be copied over to the final page.
|
||||
|
||||
###### Style Sheets (`/site/themes/citra-bs-theme/static/css/*.css`)
|
||||
The `css` folder has stylesheets that describe the aesthetics of the page.
|
||||
|
||||
###### Fonts (`/site/themes/citra-bs-theme/static/fonts/*`)
|
||||
The `fonts` folder has fonts. Wow.
|
||||
|
||||
###### Images (`/site/themes/citra-bs-theme/static/images/*`)
|
||||
The `images` folder has images for the main page, mostly branding. Other images like screenshots go in `/site/static/images/`.
|
||||
|
||||
###### Scripts (`/site/themes/citra-bs-theme/static/scripts/*.js`)
|
||||
The `scripts` folder has Javascript scripts responsible for loading special parts of the page.
|
||||
|
||||
###### Favorite Icon (`/site/themes/citra-bs-theme/static/favicon.ico`)
|
||||
The icon for the site.
|
||||
|
||||
##### Theme Metadata (`/site/themes/citra-bs-theme/theme.toml`)
|
||||
The `theme.toml` file has metadata about the Citra Bootstrap theme. Documentation for this file can be found [here](https://gohugo.io/overview/configuration/).
|
||||
|
||||
#### Configuration (`/site/config.toml`)
|
||||
The `config.toml` file contains metadata for the whole site. Documentation for this file can be found [here](https://gohugo.io/overview/configuration/).
|
||||
|
||||
### Scripts
|
||||
These are Node.JS apps used for specific purposes like fetching tweets from Twitter.
|
184
gulpfile.js
|
@ -1,79 +1,131 @@
|
|||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var exec = require('child_process').exec;
|
||||
var rimraf = require('rimraf');
|
||||
const gulp = require('gulp');
|
||||
const fs = require('fs');
|
||||
const util = require('gulp-util');
|
||||
const merge = require('merge-stream');
|
||||
const exec = require('child_process').exec;
|
||||
const sass = require('gulp-sass');
|
||||
const postcss = require('gulp-postcss');
|
||||
const cssnano = require('cssnano');
|
||||
const browserSync = require('browser-sync').create();
|
||||
const concat = require('gulp-concat');
|
||||
const imageResize = require('gulp-image-resize');
|
||||
|
||||
var postcss = require('gulp-postcss');
|
||||
var cssImport = require('postcss-import');
|
||||
var cssnext = require('postcss-cssnext');
|
||||
|
||||
var md5 = require("gulp-md5-plus");
|
||||
|
||||
var ghPages = require('gulp-gh-pages');
|
||||
|
||||
var uncss = require('gulp-uncss');
|
||||
var cleanCSS = require('gulp-clean-css');
|
||||
var image = require('gulp-image');
|
||||
var jimp = require("gulp-jimp-resize");
|
||||
|
||||
var htmlmin = require('gulp-htmlmin');
|
||||
|
||||
const distPath = './site/public';
|
||||
const cname = 'citra-emu.org';
|
||||
const deployOptions = {
|
||||
remoteUrl: "git@github.com:CitraBotWeb/CitraBotWeb.github.io.git",
|
||||
branch: "master"
|
||||
};
|
||||
|
||||
gulp.task("default", ['html']);
|
||||
|
||||
gulp.task('setup', function(cb) {
|
||||
process.env.HUGO_ENV = 'PRD';
|
||||
process.env.GULP = 'true';
|
||||
rimraf(`${distPath}`, cb);
|
||||
gulp.task('scripts:games', function (callback) {
|
||||
exec(`cd ./scripts/games/ && yarn install && node app.js`, function (err, stdout, stderr) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('hugo', ['setup'], function (cb) {
|
||||
exec('hugo -s ./site/ -v', function (err, stdout, stderr) {
|
||||
gulp.task('scripts:twitter', function (callback) {
|
||||
exec(`cd ./scripts/twitter/ && yarn install && node app.js`, function (err, stdout, stderr) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('scripts:wiki', function (callback) {
|
||||
exec(`cd ./scripts/wiki/ && yarn install && node app.js`, function (err, stdout, stderr) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('assets:images', function() {
|
||||
var baseImages = gulp.src(`build/images/*`, {base: './'})
|
||||
.pipe(gulp.dest('./'));
|
||||
var jumbotronImages = gulp.src(`build/images/jumbotron/*`, {base: './'})
|
||||
.pipe(imageResize({ width: 786, height: 471, crop: true }))
|
||||
.pipe(gulp.dest('./'));
|
||||
var bannerImages = gulp.src(`build/images/banners/*`, {base: './'})
|
||||
.pipe(imageResize({ width: 824, height: 306, crop: false }))
|
||||
.pipe(gulp.dest('./'));
|
||||
var boxartImages = gulp.src(`build/images/game/boxart/*`, {base: './'})
|
||||
.pipe(imageResize({ width: 328, height: 300, crop: true }))
|
||||
.pipe(gulp.dest('./'));
|
||||
var iconImages = gulp.src(`build/images/game/icons/*`, {base: './'})
|
||||
.pipe(imageResize({ width: 48, height: 48, crop: true }))
|
||||
.pipe(gulp.dest('./'));
|
||||
var screenshotImages = gulp.src(`build/images/screenshots/*`)
|
||||
.pipe(imageResize({ width: 400, height: 240, crop: false }))
|
||||
.pipe(gulp.dest(`build/images/screenshots/thumbs`));
|
||||
|
||||
return merge(baseImages, jumbotronImages, bannerImages, boxartImages, iconImages, screenshotImages);
|
||||
});
|
||||
|
||||
gulp.task('assets:js', function() {
|
||||
return gulp.src(['src/js/**/*.js'])
|
||||
.pipe(concat('script.js'))
|
||||
.pipe(gulp.dest('build/js'));
|
||||
});
|
||||
|
||||
gulp.task('assets:fonts', function(){
|
||||
return gulp.src('./node_modules/bootstrap-sass/assets/fonts/**/*')
|
||||
.pipe(gulp.dest('build/fonts/'))
|
||||
});
|
||||
|
||||
gulp.task('assets:scss', function () {
|
||||
var postCssOptions = [ cssnano ];
|
||||
return gulp.src('src/scss/style.scss')
|
||||
.pipe(sass().on('error', sass.logError))
|
||||
.pipe(postcss(postCssOptions))
|
||||
.pipe(gulp.dest('build/css'))
|
||||
.pipe(browserSync.stream());
|
||||
});
|
||||
|
||||
gulp.task('hugo', function (cb) {
|
||||
exec('hugo -s ./site/ -d ../build/ -v', function (err, stdout, stderr) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task("css", ['hugo'], () => (
|
||||
gulp.src(`${distPath}/css/**/*.css`, {base: './'})
|
||||
.pipe(postcss([cssnext(), cssImport({from: `${distPath}/css/main.css`})]))
|
||||
.pipe(cleanCSS())
|
||||
.pipe(md5(10, `${distPath}/**/*.html`))
|
||||
.pipe(gulp.dest('./'))
|
||||
));
|
||||
gulp.task('final:serve', function(done) {
|
||||
browserSync.init({
|
||||
open: false,
|
||||
server: {
|
||||
baseDir: 'build'
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('images', ['hugo'], () => (
|
||||
gulp.src(`${distPath}/images/*`, {base: './'})
|
||||
.pipe(gulp.dest('./')),
|
||||
gulp.src(`${distPath}/images/jumbotron/*`, {base: './'})
|
||||
.pipe(jimp({ sizes: [{"width": 786, "height": 471 }] }))
|
||||
.pipe(gulp.dest('./')),
|
||||
gulp.src(`${distPath}/images/banners/*`, {base: './'})
|
||||
.pipe(jimp({ sizes: [{"width": 824, "height": 306 }] }))
|
||||
.pipe(gulp.dest('./')),
|
||||
gulp.src(`${distPath}/images/game/boxart/*`, {base: './'})
|
||||
.pipe(jimp({ sizes: [{"width": 328, "height": 300 }] }))
|
||||
.pipe(gulp.dest('./')),
|
||||
gulp.src(`${distPath}/images/game/icons/*`, {base: './'})
|
||||
.pipe(jimp({ sizes: [{"width": 48, "height": 48 }] }))
|
||||
.pipe(gulp.dest('./'))
|
||||
));
|
||||
gulp.watch('src/js/**/*', gulp.series('assets:js'));
|
||||
gulp.watch('src/scss/**/*', gulp.series('assets:scss'));
|
||||
gulp.watch('site/**/*.html', gulp.series('hugo'));
|
||||
gulp.watch('site/**/*.md', gulp.series('hugo'));
|
||||
|
||||
gulp.task('html', ['hugo', 'css', 'images'], () => (
|
||||
gulp.src(`${distPath}/**/*.html`, {base: './'})
|
||||
.pipe(htmlmin({collapseWhitespace: true}))
|
||||
.pipe(gulp.dest('./'))
|
||||
));
|
||||
gulp.watch('build/**/*').on('change', function(x) {
|
||||
browserSync.reload(x);
|
||||
});
|
||||
|
||||
gulp.task('deploy', ['hugo', 'css', 'images', 'html'], () => {
|
||||
require('fs').writeFileSync(`${distPath}/CNAME`, `${cname}`);
|
||||
require('fs').writeFileSync(`${distPath}/robots.txt`, `Sitemap: https://${cname}/sitemap.xml\n\nUser-agent: *`);
|
||||
return gulp.src(`${distPath}/**/*`).pipe(ghPages(deployOptions));
|
||||
done()
|
||||
});
|
||||
|
||||
gulp.task('final:publish', function(done) {
|
||||
fs.writeFileSync(`build/CNAME`, `${cname}`);
|
||||
fs.writeFileSync(`build/robots.txt`, `Sitemap: https://${cname}/sitemap.xml\n\nUser-agent: *`);
|
||||
done()
|
||||
});
|
||||
|
||||
const cname = 'citra-emu.org';
|
||||
var finalCommand = null;
|
||||
|
||||
if (util.env.production) {
|
||||
process.env.HUGO_ENV = 'PRD';
|
||||
process.env.HUGO_BASEURL = `https://${cname}`
|
||||
finalCommand = 'final:publish';
|
||||
} else {
|
||||
process.env.HUGO_ENV = 'DEV';
|
||||
process.env.HUGO_BASEURL = 'http://localhost:3000';
|
||||
finalCommand = 'final:serve';
|
||||
}
|
||||
|
||||
util.log(`process.env.HUGO_ENV = '${process.env.HUGO_ENV}'`);
|
||||
util.log(`process.env.HUGO_BASEURL = '${process.env.HUGO_BASEURL}'`);
|
||||
|
||||
gulp.task('default', gulp.series(gulp.parallel('assets:js', 'assets:fonts', 'assets:scss'), 'hugo', 'assets:images', finalCommand))
|
||||
gulp.task('all', gulp.series(gulp.parallel('scripts:games', 'scripts:twitter', 'scripts:wiki'), gulp.parallel('assets:js', 'assets:fonts', 'assets:scss'), 'hugo', 'assets:images', finalCommand))
|
||||
gulp.task('content', gulp.series('hugo', finalCommand));
|
28
package.json
|
@ -3,20 +3,22 @@
|
|||
"version": "1.0.0",
|
||||
"description": "The Citra Official Website",
|
||||
"author": "",
|
||||
"license": "GPLv3",
|
||||
"license": "AGPLv3",
|
||||
"dependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-clean-css": "^3.0.3",
|
||||
"gulp-gh-pages": "^0.5.4",
|
||||
"gulp-htmlmin": "^3.0.0",
|
||||
"gulp-image": "^2.7.5",
|
||||
"gulp-jimp-resize": "^2.0.2",
|
||||
"gulp-md5-plus": "^0.2.5",
|
||||
"gulp-postcss": "^6.3.0",
|
||||
"gulp-uncss": "^1.0.6",
|
||||
"bootstrap-sass": "^3.3.7",
|
||||
"browser-sync": "^2.18.13",
|
||||
"cssnano": "^4.1.7",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-changed": "^3.1.0",
|
||||
"gulp-clean-css": "^4.0.0",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-htmlmin": "^5.0.1",
|
||||
"gulp-image-resize": "^0.13.0",
|
||||
"gulp-md5-plus": "^1.0.3",
|
||||
"gulp-postcss": "^8.0.0",
|
||||
"gulp-sass": "^4.0.2",
|
||||
"gulp-util": "^3.0.8",
|
||||
"postcss-cssnext": "^2.9.0",
|
||||
"postcss-import": "^8.2.0",
|
||||
"rimraf": "^2.6.1"
|
||||
"merge-stream": "^1.0.1",
|
||||
"yarn": "^1.12.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,182 +1,129 @@
|
|||
const fs = require('fs');
|
||||
const fsextra = require('fs-extra');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const util = require('util');
|
||||
const logger = require('winston');
|
||||
|
||||
const sanitizeHtml = require('sanitize-html');
|
||||
|
||||
const toml = require('toml');
|
||||
const blackfriday = require('./blackfriday.js');
|
||||
|
||||
const del = require('delete');
|
||||
const request = require('request-promise');
|
||||
const tomlify = require('tomlify-j0.4');
|
||||
const exec = require('sync-exec');
|
||||
|
||||
const inputDirectoryGame = './citra-games-wiki';
|
||||
const inputDirectoryWiki = './citra-games-wiki.wiki';
|
||||
const outputDirectoryMd = '../../site/content/game';
|
||||
const outputDirectoryBoxart = '../../site/static/images/game/boxart';
|
||||
const outputDirectoryIcons = '../../site/static/images/game/icons';
|
||||
const outputDirectoryScreenshots = '../../site/static/images/screenshots0';
|
||||
const outputDirectorySavefiles = '../../site/static/savefiles/';
|
||||
const fsPathCode = './citra-games-wiki/games'
|
||||
const fsPathWiki = './citra-games-wiki.wiki'
|
||||
const fsPathHugoContent = '../../site/content/game'
|
||||
const fsPathHugoBoxart = '../../site/static/images/game/boxart'
|
||||
const fsPathHugoIcon = '../../site/static/images/game/icons'
|
||||
const fsPathHugoScreenshots = '../../site/static/images/screenshots0'
|
||||
const fsPathHugoSavefiles = '../../site/static/savefiles/'
|
||||
|
||||
// The URL
|
||||
function url(title) {
|
||||
return '/wiki/' + title.replace(/\s+/g, '-').toLowerCase();
|
||||
}
|
||||
process.on('unhandledRejection', err => {
|
||||
logger.error('Unhandled rejection on process.');
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
function gitPull(directory, repository) {
|
||||
if (fs.existsSync(directory)) {
|
||||
logger.info(`Fetching latest from Github : ${directory}`);
|
||||
logger.info(`git --git-dir=${directory} pull`);
|
||||
exec(`git --git-dir=${directory} pull`);
|
||||
logger.info(`Fetching latest from Github : ${directory}`);
|
||||
logger.info(`git --git-dir=${directory} pull`);
|
||||
exec(`git --git-dir=${directory} pull`);
|
||||
} else {
|
||||
logger.info(`Cloning repository from Github : ${directory}`);
|
||||
logger.info(`git clone ${repository}`);
|
||||
exec(`git clone ${repository}`);
|
||||
logger.info(`Cloning repository from Github : ${directory}`);
|
||||
logger.info(`git clone ${repository}`);
|
||||
exec(`git clone ${repository}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getDirectories (srcpath) {
|
||||
return fs.readdirSync(srcpath)
|
||||
.filter(file => fs.lstatSync(path.join(srcpath, file)).isDirectory())
|
||||
async function getDirectories(x) {
|
||||
return fs.readdir(x).filter(file => fs.lstatSync(path.join(x, file)).isDirectory())
|
||||
}
|
||||
|
||||
// Fetch game information stored in Github repository.
|
||||
gitPull(inputDirectoryGame, 'https://github.com/citra-emu/citra-games-wiki.git');
|
||||
async function run() {
|
||||
// Make sure the output directories in Hugo exist.
|
||||
[fsPathHugoContent, fsPathHugoBoxart, fsPathHugoIcon, fsPathHugoSavefiles, fsPathHugoScreenshots].forEach(function (path) {
|
||||
if (fs.existsSync(path) == false) {
|
||||
logger.info(`Creating Hugo output directory: ${path}`);
|
||||
fs.ensureDirSync(path);
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch game articles stored in Github wiki.
|
||||
gitPull(inputDirectoryWiki, 'https://github.com/citra-emu/citra-games-wiki.wiki.git');
|
||||
// Fetch game files stored in games-wiki repository.
|
||||
gitPull('./citra-games-wiki', 'https://github.com/citra-emu/citra-games-wiki.git');
|
||||
|
||||
// Make sure the output directories in Hugo exist.
|
||||
if (fs.existsSync(outputDirectoryMd) == false) {
|
||||
logger.info(`Creating missing output directory: ${outputDirectoryMd}`);
|
||||
fs.mkdirSync(outputDirectoryMd);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputDirectoryBoxart) == false) {
|
||||
logger.info(`Creating missing output directory: ${outputDirectoryBoxart}`);
|
||||
fs.mkdirSync(outputDirectoryBoxart);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputDirectoryIcons) == false) {
|
||||
logger.info(`Creating missing output directory: ${outputDirectoryIcons}`);
|
||||
fs.mkdirSync(outputDirectoryIcons);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputDirectorySavefiles) == false) {
|
||||
logger.info(`Creating missing output directory: ${outputDirectorySavefiles}`);
|
||||
fs.mkdirSync(outputDirectorySavefiles);
|
||||
}
|
||||
|
||||
if (fs.existsSync(outputDirectoryScreenshots) == false) {
|
||||
logger.info(`Creating missing output directory: ${outputDirectoryScreenshots}`);
|
||||
fs.mkdirSync(outputDirectoryScreenshots);
|
||||
}
|
||||
|
||||
try {
|
||||
// Loop through each game folder.
|
||||
getDirectories(inputDirectoryGame).forEach(function(game) {
|
||||
// Loop through each game and process it.
|
||||
let games = await request.get({ uri: 'https://api.citra-emu.org/gamedb/websiteFeed/', json: true })
|
||||
await Promise.all(games.map(async (x) => {
|
||||
try {
|
||||
if (game == '.git') { return; }
|
||||
logger.info(`Processing game: ${x.id}`);
|
||||
|
||||
logger.info(`Creating Hugo files for ${game}`);
|
||||
// Set metadata.
|
||||
x.date = `${new Date().toISOString()}`
|
||||
|
||||
// In Hugo, data keys need to be strings.
|
||||
x.compatibility = x.compatibility.toString()
|
||||
|
||||
// Hugo requires compatibility to be a string to link to data JSON.
|
||||
x.testcases.forEach(x => x.compatibility = x.compatibility.toString())
|
||||
|
||||
x.issues = x.issues.filter(x => x.state === 'open') || []
|
||||
|
||||
// Copy the boxart for the game.
|
||||
let boxartPath = `${inputDirectoryGame}/${game}/boxart.png`;
|
||||
if (fs.existsSync(boxartPath)) {
|
||||
fsextra.copySync(boxartPath, `${outputDirectoryBoxart}/${game}.png`);
|
||||
}
|
||||
fs.copySync(`${fsPathCode}/${x.id}/boxart.png`, `${fsPathHugoBoxart}/${x.id}.png`);
|
||||
|
||||
// Copy the icon for the game.
|
||||
let iconPath = `${inputDirectoryGame}/${game}/icon.png`;
|
||||
if (fs.existsSync(iconPath)) {
|
||||
fsextra.copySync(iconPath, `${outputDirectoryIcons}/${game}.png`);
|
||||
}
|
||||
fs.copySync(`${fsPathCode}/${x.id}/icon.png`, `${fsPathHugoIcon}/${x.id}.png`);
|
||||
|
||||
// Copy the savefiles for the game.
|
||||
let inputDirectorySavefilesGame = `${inputDirectoryGame}/${game}/savefiles/`;
|
||||
let outputDirectorySavefilesGame = `${outputDirectorySavefiles}/${game}/`;
|
||||
let savefileMetadataContents = [];
|
||||
|
||||
if (fs.existsSync(inputDirectorySavefilesGame)) {
|
||||
// Create the savefile directory for each game.
|
||||
if (fs.existsSync(outputDirectorySavefilesGame) == false) {
|
||||
fs.mkdirSync(outputDirectorySavefilesGame);
|
||||
// SAVEFILE BLOCK
|
||||
var fsPathCodeSavefilesGame = `${fsPathCode}/${x.id}/savefiles/`;
|
||||
var fsPathHugoSavefilesGame = `${fsPathHugoSavefiles}/${x.id}/`;
|
||||
if (fs.existsSync(fsPathCodeSavefilesGame)) {
|
||||
// Create the savefile directory for the game.
|
||||
if (fs.existsSync(fsPathHugoSavefilesGame) == false) {
|
||||
fs.mkdirSync(fsPathHugoSavefilesGame);
|
||||
}
|
||||
|
||||
// Copy all savefiles into the output folder and store their contents.
|
||||
fs.readdirSync(inputDirectorySavefilesGame).forEach(file => {
|
||||
// Copy all savefiles into the output folder, and read their data.
|
||||
fs.readdirSync(fsPathCodeSavefilesGame).forEach(file => {
|
||||
if (path.extname(file) == '.zip') {
|
||||
fsextra.copySync(`${inputDirectorySavefilesGame}/${file}`, `${outputDirectorySavefilesGame}/${file.replace('.zip', '.zip')}`);
|
||||
} else if (path.extname(file) == '.dat') {
|
||||
// Store the contents of the file in memory for adding it into the markdown later.
|
||||
savefileMetadataContents.push({ filename: file.replace('.dat', '.zip'), contents: fs.readFileSync(`${inputDirectorySavefilesGame}/${file}`, 'utf8') });
|
||||
fs.copySync(`${fsPathCodeSavefilesGame}/${file}`, `${fsPathHugoSavefilesGame}/${file}`);
|
||||
}
|
||||
});
|
||||
// Finished copying all savefiles into the output folder, and reading their data.
|
||||
}
|
||||
// END SAVEFILE BLOCK
|
||||
|
||||
// Copy the screenshots for the game.
|
||||
let inputDirectoryScreenshotsGame = `${inputDirectoryGame}/${game}/screenshots/`;
|
||||
let outputDirectoryScreenshotsGame = `${outputDirectoryScreenshots}/${game}/`;
|
||||
|
||||
if (fs.existsSync(inputDirectoryScreenshotsGame)) {
|
||||
let fsPathScreenshotInputGame = `${fsPathCode}/${x.id}/screenshots/`;
|
||||
let fsPathScreenshotOutputGame = `${fsPathHugoScreenshots}/${x.id}/`;
|
||||
if (fs.existsSync(fsPathScreenshotInputGame)) {
|
||||
// Create the savefile directory for each game.
|
||||
if (fs.existsSync(outputDirectoryScreenshotsGame) == false) {
|
||||
fs.mkdirSync(outputDirectoryScreenshotsGame);
|
||||
if (fs.existsSync(fsPathScreenshotOutputGame) == false) {
|
||||
fs.mkdirSync(fsPathScreenshotOutputGame);
|
||||
}
|
||||
|
||||
// Copy all screenshots into the output folder.
|
||||
fs.readdirSync(inputDirectoryScreenshotsGame).forEach(file => {
|
||||
fs.readdirSync(fsPathScreenshotInputGame).forEach(file => {
|
||||
if (path.extname(file) == '.png') {
|
||||
fsextra.copySync(`${inputDirectoryScreenshotsGame}/${file}`, `${outputDirectoryScreenshotsGame}/${file}`);
|
||||
fs.copySync(`${fsPathScreenshotInputGame}/${file}`, `${fsPathScreenshotOutputGame}/${file}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Create the markdown file to be displayed in Hugo.
|
||||
let title = game.replace(/-/g, ' ').slice(0, -3);
|
||||
var stats = fs.statSync(`${inputDirectoryGame}/${game}/game.dat`);
|
||||
let modified = new Date(util.inspect(stats.mtime));
|
||||
// Clear out the wiki markdown so it won't be stored with the metadata.
|
||||
let wikiText = x.wiki_markdown
|
||||
x.wiki_markdown = null
|
||||
|
||||
let datContents = fs.readFileSync(`${inputDirectoryGame}/${game}/game.dat`, 'utf8');
|
||||
datContents = `date = "${modified.toISOString()}"\r\n` + datContents;
|
||||
let meta = tomlify(x, null, 2);
|
||||
let contentOutput = `+++\r\n${meta}\r\n+++\r\n\r\n${wikiText}\r\n`;
|
||||
|
||||
// Parse testcase information out of the dat to reinject as shortcut values.
|
||||
var dat = toml.parse(datContents);
|
||||
if (dat.testcases == null || dat.testcases.length == 0) {
|
||||
datContents = `compatibility = 99"\r\ntestcase_date = "2000-01-01"\r\n` + datContents;
|
||||
} else {
|
||||
let recent = dat.testcases[0];
|
||||
datContents = `compatibility = ${recent.compatibility}\r\ntestcase_date = "${recent.date}"\r\n` + datContents;
|
||||
}
|
||||
await fs.writeFile(`${fsPathHugoContent}/${x.id}.md`, contentOutput);
|
||||
|
||||
var wikiContents = "";
|
||||
let wikiPathGame = `${inputDirectoryWiki}/${game}.md`;
|
||||
if (fs.existsSync(wikiPathGame)) {
|
||||
wikiContents = fs.readFileSync(wikiPathGame, 'utf8');
|
||||
} else {
|
||||
logger.warn(`CompatDB: No wiki exists for game ${game}.`);
|
||||
wikiContents = "## No wiki exists yet for this game.";
|
||||
}
|
||||
|
||||
// Fix Blackfriday markdown rendering differences.
|
||||
wikiContents = blackfriday.fixLists(wikiContents);
|
||||
wikiContents = blackfriday.fixLinks(wikiContents);
|
||||
|
||||
// Read all savefiles from array and copy them into the markdown.
|
||||
savefileMetadataContents.forEach(function(savefile) {
|
||||
let modified = new Date(util.inspect(stats.mtime));
|
||||
datContents += `\r\n\r\n[[ savefiles ]]\r\n${savefile.contents}\r\nfilename = "${savefile.filename}"\r\ndate = "${modified.toISOString()}"\r\n`;
|
||||
});
|
||||
|
||||
let output = `+++\r\n${datContents}\r\n+++\r\n\r\n${wikiContents}\r\n`;
|
||||
fs.writeFileSync(`${outputDirectoryMd}/${game}.md`, output);
|
||||
return x
|
||||
} catch (ex) {
|
||||
logger.warn(`${game} failed to generate: ${ex}`);
|
||||
logger.warn(`${x.id} ${x.title} failed to generate: ${ex}`);
|
||||
logger.error(ex);
|
||||
throw ex
|
||||
}
|
||||
});
|
||||
} catch (ex) {
|
||||
logger.error(ex);
|
||||
}))
|
||||
}
|
||||
|
||||
// Script start
|
||||
run()
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Blackfriday markdown rendering requires a blank line before lists.
|
||||
module.exports.fixLists = function(markdown) {
|
||||
var lines = markdown.split(/\r?\n/);
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
// If it's the start of the file, ignore to prevent an index issue.
|
||||
if (i > lines.length) { return; }
|
||||
if (i == 0 || lines[i] == '\n') { continue; }
|
||||
|
||||
// Search for the start of a list designated by the * character.
|
||||
if (lines[i].startsWith("* ") && lines[i - 1].startsWith("* ") == false) {
|
||||
i = i + 1;
|
||||
lines.splice(i - 1, 0, '');
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\r\n');
|
||||
}
|
||||
|
||||
module.exports.fixLinks = function(markdown) {
|
||||
let cleaned = markdown;
|
||||
|
||||
// Replacing tags like [[Common Issues on Windows|Common Issues]]
|
||||
cleaned = markdown.replace(/\[\[(.*)\|(.*)\]\]/g, function(match, p1, p2) {
|
||||
return `[${p1}](${url(p2)})`
|
||||
});
|
||||
|
||||
// Replacing tags like [[Common Issues]]
|
||||
cleaned = markdown.replace(/\[\[(.*)\]\]/g, function(match, p1) {
|
||||
return `[${p1}](${url(p1)})`
|
||||
});
|
||||
|
||||
return cleaned;
|
||||
}
|
|
@ -1,20 +1,19 @@
|
|||
{
|
||||
"name": "citra-wiki",
|
||||
"name": "citra-games",
|
||||
"version": "1.0.0",
|
||||
"description": "Used in Citra Hugo to import Wiki articles.",
|
||||
"description": "Used by Citra to generate markdown articles for GameDb.",
|
||||
"homepage": "https://citra-emu.org/",
|
||||
"author": "Flame Sage <chris062689@gmail.com>",
|
||||
"main": "app.js",
|
||||
"dependencies": {
|
||||
"delete": "^0.3.2",
|
||||
"fs-extra": "^3.0.1",
|
||||
"rimraf": "^2.6.1",
|
||||
"sanitize-html": "^1.14.1",
|
||||
"request": "^2.81.0",
|
||||
"request-promise": "^4.2.1",
|
||||
"sync-exec": "^0.6.2",
|
||||
"toml": "^2.3.2",
|
||||
"tomlify-j0.4": "^2.0.0",
|
||||
"winston": "^2.2.0"
|
||||
},
|
||||
"preferGlobal": false,
|
||||
"private": true,
|
||||
"license": "GPLv3"
|
||||
"license": "AGPL-3.0-or-later"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
ajv@^5.1.0:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
fast-deep-equal "^1.0.0"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
|
||||
async@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
|
||||
aws4@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
bluebird@^3.5.0:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||
|
||||
boom@4.x.x:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31"
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
boom@5.x.x:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02"
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
|
||||
colors@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||
|
||||
combined-stream@1.0.6, combined-stream@~1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
cryptiles@3.x.x:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
|
||||
dependencies:
|
||||
boom "5.x.x"
|
||||
|
||||
cycle@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
|
||||
extend@~3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
|
||||
eyes@0.1.x:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
|
||||
|
||||
fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
|
||||
form-data@~2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fs-extra@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^3.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
|
||||
har-validator@~5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
|
||||
dependencies:
|
||||
ajv "^5.1.0"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
hawk@~6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"
|
||||
dependencies:
|
||||
boom "4.x.x"
|
||||
cryptiles "3.x.x"
|
||||
hoek "4.x.x"
|
||||
sntp "2.x.x"
|
||||
|
||||
hoek@4.x.x:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
|
||||
isstream@0.1.x, isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
|
||||
jsonfile@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
lodash@^4.13.1:
|
||||
version "4.17.5"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
|
||||
|
||||
mime-db@~1.33.0:
|
||||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.17:
|
||||
version "2.1.18"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
|
||||
dependencies:
|
||||
mime-db "~1.33.0"
|
||||
|
||||
oauth-sign@~0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
||||
qs@~6.5.1:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
request-promise-core@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6"
|
||||
dependencies:
|
||||
lodash "^4.13.1"
|
||||
|
||||
request-promise@^4.2.1:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.2.tgz#d1ea46d654a6ee4f8ee6a4fea1018c22911904b4"
|
||||
dependencies:
|
||||
bluebird "^3.5.0"
|
||||
request-promise-core "1.1.1"
|
||||
stealthy-require "^1.1.0"
|
||||
tough-cookie ">=2.3.3"
|
||||
|
||||
request@^2.81.0:
|
||||
version "2.83.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.6.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.1"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.1"
|
||||
har-validator "~5.0.3"
|
||||
hawk "~6.0.2"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.17"
|
||||
oauth-sign "~0.8.2"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.1"
|
||||
safe-buffer "^5.1.1"
|
||||
stringstream "~0.0.5"
|
||||
tough-cookie "~2.3.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
sntp@2.x.x:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8"
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
getpass "^0.1.1"
|
||||
optionalDependencies:
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
stack-trace@0.0.x:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
|
||||
stealthy-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
|
||||
stringstream@~0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
|
||||
|
||||
sync-exec@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105"
|
||||
|
||||
tomlify-j0.4@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tomlify-j0.4/-/tomlify-j0.4-2.2.1.tgz#60c4e7dd2066b2e917dd9a0de5fd676c0a6d7c7b"
|
||||
|
||||
tough-cookie@>=2.3.3, tough-cookie@~2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
|
||||
dependencies:
|
||||
punycode "^1.4.1"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
||||
|
||||
uuid@^3.1.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
winston@^2.2.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee"
|
||||
dependencies:
|
||||
async "~1.0.0"
|
||||
colors "1.0.x"
|
||||
cycle "1.0.x"
|
||||
eyes "0.1.x"
|
||||
isstream "0.1.x"
|
||||
stack-trace "0.0.x"
|
|
@ -11,5 +11,5 @@
|
|||
},
|
||||
"preferGlobal": false,
|
||||
"private": true,
|
||||
"license": "GPLv3"
|
||||
"license": "AGPL-3.0-or-later"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
async@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9"
|
||||
|
||||
colors@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||
|
||||
cycle@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
|
||||
|
||||
eyes@0.1.x:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
|
||||
|
||||
graceful-fs@^4.1.6:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
isstream@0.1.x:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
|
||||
jsonfile@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
stack-trace@0.0.x:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
|
||||
winston@^2.2.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee"
|
||||
dependencies:
|
||||
async "~1.0.0"
|
||||
colors "1.0.x"
|
||||
cycle "1.0.x"
|
||||
eyes "0.1.x"
|
||||
isstream "0.1.x"
|
||||
stack-trace "0.0.x"
|
|
@ -14,5 +14,5 @@
|
|||
},
|
||||
"preferGlobal": false,
|
||||
"private": true,
|
||||
"license": "GPLv3"
|
||||
"license": "AGPL-3.0-or-later"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,462 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
ansi-styles@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
arr-union@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
|
||||
|
||||
array-uniq@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
|
||||
|
||||
async-array-reduce@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/async-array-reduce/-/async-array-reduce-0.2.1.tgz#c8be010a2b5cd00dea96c81116034693dfdd82d1"
|
||||
|
||||
async@^1.5.2:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
|
||||
async@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
|
||||
bluebird@^3.3.5:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
chalk@^2.3.0, chalk@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.0"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.2.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
|
||||
dependencies:
|
||||
color-name "^1.1.1"
|
||||
|
||||
color-name@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
|
||||
colors@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
cycle@1.0.x:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
|
||||
|
||||
delete@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/delete/-/delete-0.3.2.tgz#7cfecf5ef7dfb802fad27ab8f5be5ae546c5b79e"
|
||||
dependencies:
|
||||
async "^1.5.2"
|
||||
bluebird "^3.3.5"
|
||||
extend-shallow "^2.0.1"
|
||||
lazy-cache "^1.0.4"
|
||||
matched "^0.4.1"
|
||||
rimraf "^2.5.2"
|
||||
|
||||
dom-serializer@0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
||||
dependencies:
|
||||
domelementtype "~1.1.1"
|
||||
entities "~1.1.1"
|
||||
|
||||
domelementtype@1, domelementtype@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
|
||||
|
||||
domelementtype@~1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
|
||||
|
||||
domhandler@^2.3.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259"
|
||||
dependencies:
|
||||
domelementtype "1"
|
||||
|
||||
domutils@^1.5.1:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
|
||||
dependencies:
|
||||
dom-serializer "0"
|
||||
domelementtype "1"
|
||||
|
||||
entities@^1.1.1, entities@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
|
||||
expand-tilde@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
|
||||
dependencies:
|
||||
os-homedir "^1.0.1"
|
||||
|
||||
extend-shallow@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
|
||||
dependencies:
|
||||
is-extendable "^0.1.0"
|
||||
|
||||
eyes@0.1.x:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
|
||||
|
||||
fs-exists-sync@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
|
||||
glob@^7.0.5:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
global-modules@^0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
|
||||
dependencies:
|
||||
global-prefix "^0.1.4"
|
||||
is-windows "^0.2.0"
|
||||
|
||||
global-prefix@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
|
||||
dependencies:
|
||||
homedir-polyfill "^1.0.0"
|
||||
ini "^1.3.4"
|
||||
is-windows "^0.2.0"
|
||||
which "^1.2.12"
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
|
||||
has-glob@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-0.1.1.tgz#a261c4c2a6c667e0c77b700a7f297c39ef3aa589"
|
||||
dependencies:
|
||||
is-glob "^2.0.1"
|
||||
|
||||
homedir-polyfill@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
|
||||
dependencies:
|
||||
parse-passwd "^1.0.0"
|
||||
|
||||
htmlparser2@^3.9.0:
|
||||
version "3.9.2"
|
||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
|
||||
dependencies:
|
||||
domelementtype "^1.3.0"
|
||||
domhandler "^2.3.0"
|
||||
domutils "^1.5.1"
|
||||
entities "^1.1.1"
|
||||
inherits "^2.0.1"
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.1, inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
ini@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
|
||||
is-extendable@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
|
||||
|
||||
is-extglob@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
|
||||
|
||||
is-glob@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
|
||||
dependencies:
|
||||
is-extglob "^1.0.0"
|
||||
|
||||
is-valid-glob@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
|
||||
|
||||
is-windows@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
|
||||
isstream@0.1.x:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
|
||||
kind-of@^3.0.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
|
||||
dependencies:
|
||||
is-buffer "^1.1.5"
|
||||
|
||||
lazy-cache@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||
|
||||
lazy-cache@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
|
||||
dependencies:
|
||||
set-getter "^0.1.0"
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
|
||||
lodash.escaperegexp@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
|
||||
lodash.isstring@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
|
||||
|
||||
lodash.mergewith@^4.6.0:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||
|
||||
matched@^0.4.1:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/matched/-/matched-0.4.4.tgz#56d7b7eb18033f0cf9bc52eb2090fac7dc1e89fa"
|
||||
dependencies:
|
||||
arr-union "^3.1.0"
|
||||
async-array-reduce "^0.2.0"
|
||||
extend-shallow "^2.0.1"
|
||||
fs-exists-sync "^0.1.0"
|
||||
glob "^7.0.5"
|
||||
has-glob "^0.1.1"
|
||||
is-valid-glob "^0.3.0"
|
||||
lazy-cache "^2.0.1"
|
||||
resolve-dir "^0.1.0"
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-homedir@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
|
||||
parse-passwd@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
postcss@^6.0.14:
|
||||
version "6.0.19"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555"
|
||||
dependencies:
|
||||
chalk "^2.3.1"
|
||||
source-map "^0.6.1"
|
||||
supports-color "^5.2.0"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
|
||||
readable-stream@^2.0.2:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.0.3"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
resolve-dir@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
|
||||
dependencies:
|
||||
expand-tilde "^1.2.2"
|
||||
global-modules "^0.2.3"
|
||||
|
||||
rimraf@^2.5.2, rimraf@^2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
|
||||
dependencies:
|
||||
glob "^7.0.5"
|
||||
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
sanitize-html@^1.14.1:
|
||||
version "1.18.2"
|
||||
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.18.2.tgz#61877ba5a910327e42880a28803c2fbafa8e4642"
|
||||
dependencies:
|
||||
chalk "^2.3.0"
|
||||
htmlparser2 "^3.9.0"
|
||||
lodash.clonedeep "^4.5.0"
|
||||
lodash.escaperegexp "^4.1.2"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.isstring "^4.0.1"
|
||||
lodash.mergewith "^4.6.0"
|
||||
postcss "^6.0.14"
|
||||
srcset "^1.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
set-getter@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
|
||||
dependencies:
|
||||
to-object-path "^0.3.0"
|
||||
|
||||
source-map@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
|
||||
srcset@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/srcset/-/srcset-1.0.0.tgz#a5669de12b42f3b1d5e83ed03c71046fc48f41ef"
|
||||
dependencies:
|
||||
array-uniq "^1.0.2"
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
stack-trace@0.0.x:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
|
||||
string_decoder@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
supports-color@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
sync-exec@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105"
|
||||
|
||||
to-object-path@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
||||
which@^1.2.12:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
winston@^2.2.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.0.tgz#808050b93d52661ed9fb6c26b3f0c826708b0aee"
|
||||
dependencies:
|
||||
async "~1.0.0"
|
||||
colors "1.0.x"
|
||||
cycle "1.0.x"
|
||||
eyes "0.1.x"
|
||||
isstream "0.1.x"
|
||||
stack-trace "0.0.x"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
|
@ -1,5 +1,7 @@
|
|||
baseurl = "https://citra-emu.org/"
|
||||
languageCode = "en-us"
|
||||
|
||||
DefaultContentLanguage = "en"
|
||||
theme = "citra-bs-theme"
|
||||
|
||||
# Define how many objects appear per pagination.
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
+++
|
||||
title = "Discord"
|
||||
+++
|
||||
|
||||
Please read our [most common questions](https://citra-emu.org/wiki/faq/) and our [community rules](https://citra-emu.org/rules/) before joining.
|
||||
|
||||
Review the following before joining our servers:
|
||||
|
||||
* **Piracy is prohibited** Warez/downloading games talk is prohibited. **This includes asking for system files, ROMs, encryption keys, etc.**
|
||||
|
||||
* **Do not link or discuss unofficial builds.** Citra does not provide support for unofficial builds. They may introduce new bugs, contain GPL violations, or be a virus.
|
||||
|
||||
* **Having trouble with a specific game?** Check our [Game Compatibility List](https://citra-emu.org/game/).
|
||||
|
||||
* **Want a quick answer?** Check our [most common questions](https://citra-emu.org/wiki/faq/).
|
||||
|
||||
* **Does Citra support network connectivity or online play?** Yes, Citra supports networked local WiFi, but does not support connecting to Nintendo's servers.
|
||||
|
||||
* **Are you planning to make an Android version?** No, not at the moment.
|
||||
|
||||
<div style='margin-top: 5%;'>
|
||||
<a href='https://discord.gg/FAXfZV9'>Click here to join our Discord channel.</a>
|
||||
</div>
|
|
@ -3,13 +3,46 @@ title = "Download Citra"
|
|||
advertisement = true
|
||||
+++
|
||||
|
||||
The nightly build of Citra contains already reviewed and tested features. If you require support with the installation or use of Citra, or you want to report bugs you should use this version. This version is still in development, so expect crashes and bugs.
|
||||
The nightly build of Citra contains already reviewed and tested features. If you require support with the installation
|
||||
or use of Citra, or you want to report bugs you should use this version. This version is still in development, so
|
||||
expect crashes and bugs.
|
||||
|
||||
The Bleeding Edge build of Citra is the same as our nightly builds, with additional features that are still waiting on review before making it into the official Citra builds. We will not provide support for issues found only in this version. If you believe you've found a bug, please retest on our nightly builds. This version is still in development, so expect crashes and bugs.
|
||||
The Canary build of Citra is the same as our nightly builds, with additional features that are still waiting on review
|
||||
before making it into the official Citra builds. We will not provide support for issues found only in this version. If
|
||||
you believe you've found a bug, please retest on our nightly builds. This version is still in development, so expect
|
||||
crashes and bugs.
|
||||
|
||||
---
|
||||
|
||||
<div id="updater-view">
|
||||
The Citra updater provides a easy interface to install, update and manage Citra. Unless you know what you are doing,
|
||||
this is likely what you are looking for. <b>Citra currently does not support Android or iOS, only desktop x64 systems.</b>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div class="text-center">
|
||||
<i id="dl-autodetect">Autodetected platform: XYZ</i>
|
||||
<br />
|
||||
<div id="dl-unknown">
|
||||
Unknown platform - Citra is <b>only supported</b> on 64-bit versions of Windows, macOS, and Linux.
|
||||
If you are running one of these, choose one of the options below.
|
||||
</div>
|
||||
<a href="https://github.com/citra-emu/citra-web/releases/download/1.0/citra-setup-windows.exe" class="btn btn-lg btn-primary dl-updater-button" id="dl-windows-x64">Download for Windows x64</a>
|
||||
<a href="https://github.com/citra-emu/citra-web/releases/download/1.0/citra-setup-mac.dmg" class="btn btn-lg btn-primary dl-updater-button" id="dl-mac-x64">Download for Mac x64</a>
|
||||
<a href="https://flatpak.citra-emu.org/" class="btn btn-lg btn-primary dl-updater-button" id="dl-linux-x64">Download for Linux x64</a>
|
||||
|
||||
<br />
|
||||
<span id="other-container"><a href="#" id="other-platforms-link">Other platforms</a> | </span>
|
||||
<a href="#" id="manual-link">Manual download</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="manual-view">
|
||||
<div class="visible-xs">
|
||||
<h3>Citra currently does not support Android or iOS.</h3>
|
||||
</div>
|
||||
|
||||
<a href="?" class="btn">Back</a>
|
||||
|
||||
<h3>Nightly Build <span style='font-size: smaller; margin-left: 6px;'> Last release was <span id='last-updated-nightly'></span></span></h3>
|
||||
<table id="downloads-nightly" class="table">
|
||||
|
@ -25,8 +58,8 @@ The Bleeding Edge build of Citra is the same as our nightly builds, with additio
|
|||
</table>
|
||||
<div style="text-align: center; padding: 0px; margin: 0px;"><a href = "https://github.com/citra-emu/citra-nightly/releases">Click here to view previous versions...</a></div>
|
||||
|
||||
<h3>Bleeding Edge Build <span style='font-size: smaller; margin-left: 6px;'> Last release was <span id='last-updated-bleeding-edge'></span></span></h3>
|
||||
<table id="downloads-bleeding-edge" class="table">
|
||||
<h3>Canary Build <span style='font-size: smaller; margin-left: 6px;'> Last release was <span id='last-updated-canary'></span></span></h3>
|
||||
<table id="downloads-canary" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Build Date</th>
|
||||
|
@ -37,7 +70,7 @@ The Bleeding Edge build of Citra is the same as our nightly builds, with additio
|
|||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align: center; padding: 0px; margin: 0px;"><a href = "https://github.com/citra-emu/citra-bleeding-edge/releases">Click here to view previous versions...</a></div>
|
||||
<div style="text-align: center; padding: 0px; margin: 0px;"><a href = "https://github.com/citra-emu/citra-canary/releases">Click here to view previous versions...</a></div>
|
||||
|
||||
<style>
|
||||
.table-first { background-color: #fcf8e3; }
|
||||
|
@ -45,71 +78,126 @@ The Bleeding Edge build of Citra is the same as our nightly builds, with additio
|
|||
.dl-icon img { width: 32px; height: 32px; padding: 4px; }
|
||||
.dl-icon img:hover { cursor: pointer; }
|
||||
</style>
|
||||
</div>
|
||||
|
||||
<div id="no-js-view">
|
||||
Hi! We see that you have JavaScript disabled. Unfortunately, this means that we cannot automatically
|
||||
prepare a updater for you, nor are we able to show you the latest archives of Citra either. Here are a few
|
||||
links to get you started however:<br />
|
||||
<br />
|
||||
<a href="https://github.com/citra-emu/citra-web/releases/download/1.0/citra-setup-windows.exe">Windows x64 Installer</a><br />
|
||||
<a href="https://github.com/citra-emu/citra-web/releases/download/1.0/citra-setup-mac.dmg">Mac x64 Installer</a><br />
|
||||
<a href="https://flatpak.citra-emu.org/">Download for Linux x64</a><br />
|
||||
<a href="https://github.com/citra-emu/citra-nightly/releases">Nightly Builds</a><br />
|
||||
<a href="https://github.com/citra-emu/citra-canary/releases">Canary Builds</a> <br />
|
||||
</div>
|
||||
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
function getRelease(v, count = 5) {
|
||||
$.getJSON(`https://api.github.com/repos/citra-emu/citra-${v}/releases`, function(releases) {
|
||||
$(`#last-updated-${v}`).text(moment(releases[0].published_at).fromNow());
|
||||
|
||||
for (var i = 0; i < releases.length; ++i) {
|
||||
var release = releases[i];
|
||||
let release_date = moment(release.published_at).fromNow();
|
||||
|
||||
let release_commit = release.assets[0].name.split('-').pop().trim().split('.')[0];
|
||||
let release_commit_url = `https://github.com/citra-emu/citra-${v}/commit/${release_commit}`;
|
||||
|
||||
let release_title = '';
|
||||
if (v == 'nightly') {
|
||||
release_title = 'Nightly Build';
|
||||
} else if (v == 'canary') {
|
||||
release_title = 'Canary Build';
|
||||
}
|
||||
|
||||
if (release_commit) {
|
||||
release_title += ' - ' + release_commit;
|
||||
}
|
||||
|
||||
var download_span = '';
|
||||
|
||||
var table_style = '';
|
||||
if (i == 0) { table_style = 'table-first'; }
|
||||
|
||||
release.assets.forEach(function(asset) {
|
||||
if (asset.name.includes('nupkg')) return;
|
||||
if (asset.name.includes('.7z')) return;
|
||||
if (asset.name.includes('RELEASES')) return;
|
||||
|
||||
/* We only want to provide mingw builds on the downloads page. */
|
||||
if (asset.name.includes('-msvc-')) return;
|
||||
|
||||
let env_icon = './images/icons/file.png';
|
||||
if (asset.name.includes('windows')) env_icon = '/images/icons/windows.png';
|
||||
else if (asset.name.includes('exe')) env_icon = '/images/icons/windows.png';
|
||||
else if (asset.name.includes('osx')) env_icon = '/images/icons/apple.png';
|
||||
else if (asset.name.includes('linux')) env_icon = '/images/icons/linux.png';
|
||||
|
||||
let download_url = `https://github.com/citra-emu/citra-${v}/releases/download/${release.tag_name}/${asset.name}`;
|
||||
download_span += `<a class="dl-icon" href="${download_url}"><img src="${env_icon}"></i></a>`;
|
||||
});
|
||||
|
||||
/* Generate the link to the Github release. */
|
||||
download_span += `<a class="dl-icon" href="${release.html_url}"><img src="/images/icons/github.png"></i></a>`;
|
||||
|
||||
if (release_commit_url != null) {
|
||||
$(`#downloads-${v}`).append(`<tr class="${table_style}"><td>${release_date}</td>` +
|
||||
`<td><a href="${release_commit_url}">${release_title}</a></td><td>${download_span}</td></tr>`);
|
||||
} else {
|
||||
$(`#downloads-${v}`).append(`<tr class="${table_style}"><td>${release_date}</td>` +
|
||||
`<td>${release_title}</td><td>${download_span}</td></tr>`);
|
||||
}
|
||||
if (i + 1 >= count) { break; }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function fetchReleases() {
|
||||
getRelease('nightly');
|
||||
getRelease('bleeding-edge');
|
||||
|
||||
function getRelease(v, count = 5) {
|
||||
$.getJSON('https://api.github.com/repos/citra-emu/citra-' + v + '/releases', function(releases) {
|
||||
$("#last-updated-" + v).text(moment(releases[0].published_at).fromNow());
|
||||
|
||||
for (var i = 0; i < releases.length; ++i) {
|
||||
var release = releases[i];
|
||||
let release_date = moment(release.published_at).fromNow();
|
||||
|
||||
let release_commit = null;
|
||||
let release_commit_url = null;
|
||||
if (v == 'nightly') {
|
||||
release_commit = release.assets[0].name.split('-').pop().trim().split('.')[0];
|
||||
release_commit_url = 'https://github.com/citra-emu/citra-' + v + '/commit/' + release_commit;
|
||||
}
|
||||
|
||||
let release_title = '';
|
||||
if (v == 'nightly') {
|
||||
release_title = 'Nightly Build';
|
||||
} else if (v == 'bleeding-edge') {
|
||||
release_title = 'Bleeding Edge Build';
|
||||
}
|
||||
|
||||
if (release_commit) {
|
||||
release_title += ' - ' + release_commit;
|
||||
}
|
||||
|
||||
var download_span = '';
|
||||
|
||||
var table_style = '';
|
||||
if (i == 0) { table_style = 'table-first'; }
|
||||
|
||||
release.assets.forEach(function(asset) {
|
||||
if (asset.name.includes('nupkg')) return;
|
||||
if (asset.name.includes('RELEASES')) return;
|
||||
|
||||
let env_icon = './images/icons/file.png';
|
||||
if (asset.name.includes('windows')) env_icon = '/images/icons/windows.png';
|
||||
else if (asset.name.includes('exe')) env_icon = '/images/icons/windows.png';
|
||||
else if (asset.name.includes('osx')) env_icon = '/images/icons/apple.png';
|
||||
else if (asset.name.includes('linux')) env_icon = '/images/icons/linux.png';
|
||||
|
||||
let download_url = 'https://github.com/citra-emu/citra-' + v + '/releases/download/' + release.tag_name + '/' + asset.name;
|
||||
download_span += '<a class="dl-icon" href="' + download_url + '"><img src="' + env_icon + '"></i></a>';
|
||||
});
|
||||
|
||||
// Generate the link to the Github release.
|
||||
download_span += '<a class="dl-icon" href="' + release.html_url + '"><img src="/images/icons/github.png"></i></a>';
|
||||
|
||||
if (release_commit_url != null) {
|
||||
$('#downloads-' + v).append('<tr class="' + table_style + '"><td>' + release_date + '</td>' +
|
||||
'<td><a href="' + release_commit_url + '/">' + release_title + '</a></td><td>' + download_span + '</td></tr>');
|
||||
} else {
|
||||
$('#downloads-' + v).append('<tr class="' + table_style + '"><td>' + release_date + '</td>' +
|
||||
'<td>' + release_title + '</td><td>' + download_span + '</td></tr>');
|
||||
}
|
||||
if (i + 1 >= count) { break; }
|
||||
};
|
||||
});
|
||||
getRelease('canary');
|
||||
}
|
||||
|
||||
// Attempt autodetection of their operating system
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
var allPlatforms = ["windows", "mac", "linux"];
|
||||
|
||||
var os = undefined;
|
||||
if (userAgent.indexOf("windows") !== -1) {
|
||||
os = "Windows";
|
||||
} else if (userAgent.indexOf("mac") !== -1 && userAgent.indexOf("mobile") === -1 && userAgent.indexOf("phone") === -1) {
|
||||
os = "Mac";
|
||||
} else if (userAgent.indexOf("linux") !== -1 && userAgent.indexOf("android") === -1) {
|
||||
os = "Linux";
|
||||
}
|
||||
|
||||
if (os !== undefined) {
|
||||
$("#dl-" + os.toLowerCase() + "-x64").css("display", "block");
|
||||
|
||||
var autodetect = $("#dl-autodetect");
|
||||
autodetect.text("Autodetected platform: " + os);
|
||||
autodetect.css("display", "inline");
|
||||
} else {
|
||||
$("#dl-unknown").css("display", "block");
|
||||
}
|
||||
|
||||
$("#no-js-view").css("display", "none");
|
||||
$("#updater-view").css("display", "block");
|
||||
|
||||
$("#other-platforms-link").click(function() {
|
||||
for (var i = 0; i < allPlatforms.length; i++) {
|
||||
var platform = allPlatforms[i];
|
||||
$("#dl-" + platform + "-x64").css("display", "block");
|
||||
$("#other-container").css("display", "none");
|
||||
}
|
||||
});
|
||||
|
||||
$("#manual-link").click(function() {
|
||||
$("#updater-view").css("display", "none");
|
||||
$("#manual-view").css("display", "block");
|
||||
fetchReleases();
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
+++
|
||||
date = "2018-12-07T08:00:00-08:00"
|
||||
title = "Accurate Audio Emulation Has Arrived"
|
||||
tags = [ "feature-update" ]
|
||||
author = "jroweboy"
|
||||
banner = "accurate-audio-emulation.png"
|
||||
forum = 67781
|
||||
+++
|
||||
|
||||
## Pokémon X / Y and Many More Games Are Finally Working!
|
||||
|
||||
You've been asking for it for years now, and we've been listening, we promise!
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/pokemonleague.png"
|
||||
title="The Pokémon league awaits your challenge!"
|
||||
>}}
|
||||
|
||||
<!--more-->
|
||||
|
||||
Thanks to the hard work of one of our very talented developers, some of Citra's longest standing issues are finally fixed! Special thanks to all those who are supporting these efforts on [Patreon](https://www.patreon.com/citraemu). These donations are given directly to support the hardworking developers such as [wwylele](https://github.com/wwylele/) who spent almost an entire year of his spare time on the feature in this blog post! We love working on this project, and have a whole lot more to talk about in the coming weeks!
|
||||
|
||||
It's been a long time in development, but we are finally pleased to announce that many of the oldest bugs in Citra are now fixed in the latest Canary build thanks to the tireless efforts of [wwylele](https://github.com/wwylele/).
|
||||
Among the titles that had issues with Citra's HLE audio emulation, one stands out as the number one most requested game of all time: Pokémon X and Y.
|
||||
Before we get too much into the long story behind this great achievement, we should set expectations for what this means for the users of the emulator.
|
||||
|
||||
## F.A.Q
|
||||
|
||||
* What games are now working?
|
||||
|
||||
We've been able to test a few of the fan favorites such as Pokémon X / Y, Fire Emblem Fates and Echoes, and many more! If you've experienced audio crashes or bugs in the past, now's the best time to try those games out again and help us find any issues with this new accurate audio feature.
|
||||
|
||||
* How can I test it out?
|
||||
|
||||
In the Audio tab of the Configuration menu, there is a new option for Emulation. Selecting "LLE (Accurate)" will use the new feature, while the default value "HLE (Fast)" will continue to use the original audio code.
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/configuration.png"
|
||||
title="You can find the dropdown here. Keep in mind you cannot switch between Fast and Accurate while a game is running"
|
||||
>}}
|
||||
|
||||
* Why is it so slow on every game?
|
||||
|
||||
**We still recommend using HLE (Fast) Audio emulation until further speed improvements are added to LLE (Accurate) emulation! Today we are pleased to announce that many bugs are fixed, but we are also aware that LLE (Accurate) audio makes every game run at around 5FPS or less!**
|
||||
|
||||
As you'll see in the rest of the article, this feature has been in development by a single developer for almost a whole year now. During this time, the focus was on accurate emulation, but now that it's released, we can and will put effort into optimizing it.
|
||||
|
||||
* What will happen to the current fast audio emulation?
|
||||
|
||||
It's not going anywhere! In fact, thanks to this new accurate audio emulation option, it should help developers make it even better so it will work with every game.
|
||||
|
||||
* How long will it take for games to be full speed with Accurate Audio?
|
||||
|
||||
We can't ever say for sure, but we really hope that it'll be soon! We've done some preliminary profiling and can confidently say that there's plenty of room for improvement, but now that the code change is live, we welcome any and all contributions to the [Teakra project](https://github.com/wwylele/teakra).
|
||||
|
||||
---
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/levelup.png"
|
||||
title="With the level up freeze fixed, Citra has levelled up too!"
|
||||
>}}
|
||||
|
||||
With that out of the way, buckle up as it's now time to dive into the storied history behind the fix for Citra's most prolific bug yet!
|
||||
|
||||
## All About HLE Audio And Why It's Awesome
|
||||
|
||||
Take a trip down memory lane, and you'll dig up a blog post from 2016 titled ["HLE Audio Comes to Citra"](https://citra-emu.org/entry/hle-audio-comes-to-citra/).
|
||||
Written by the very talented [MerryMage](https://github.com/MerryMage/), High Level Audio Emulation (or HLE audio for short) provides excellent audio quality while also being very efficient.
|
||||
So for emulation, where the goal of many developers is not only to make the emulation accurate, but also to make it *fast*, HLE audio is a great middle ground as you get to have high accuracy while also taking almost no processing effort.
|
||||
But as usual, there is one thing that's particularly hard to get right with HLE audio.
|
||||
In order to write an effective HLE audio engine, one must first reverse engineer the audio code that the game uses, and truly understand what it does.
|
||||
|
||||
[merry](https://github.com/MerryMage/) spent a long time writing tools to help break down exactly what the game was doing, and also decipher what the audio code is doing *semantically*.
|
||||
This turns out to be pretty tricky in practice.
|
||||
It's much simpler to look at disassembly and see what the code is doing than it is to really understand why it's doing something, which is a requirement when recreating the audio code.
|
||||
Simply put, writing HLE audio support means diving deep into how the code for the game's audio works, and recreating its functionality in Citra, without ever running any actual audio code from the game.
|
||||
But there's a very different way to handle audio, and this is hinted about at the end of the 2016 article: Low Level Audio Emulation (or LLE for short).
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/echoes.png"
|
||||
title="Fire Emblem Echoes: Shadows of Valentia can get past the intro now as well"
|
||||
>}}
|
||||
|
||||
## Debugging Pokémon X Told Us That It's Broken but not WHY
|
||||
|
||||
Before looking in depth at what LLE audio emulation is all about, a quick diversion into the debugging effort that went into Pokémon X / Y is in order.
|
||||
Looking at the [Citra YouTube channel](https://www.youtube.com/channel/UC_dcdgzuapBtAY4ol3x-90Q), one will find several videos talking about the games' progress!
|
||||
At the time, we were just as excited as everyone else to see how well the games were advancing, but at some point, they stopped getting better.
|
||||
After CRO support landed to get the games running (thanks to both [Subv](https://github.com/Subv/) and [wwylele](https://github.com/wwylele/)), several fixes to the 3DS GPU emulation, followed by geometry shader support (thanks to the hard work of [neobrain](https://github.com/neobrain/), [JayFoxRox](https://github.com/JayFoxRox/), [ds84182](https://github.com/ds84182), and once again [wwylele](https://github.com/wwylele/)), we really hoped that the games would finally start working!
|
||||
But as everyone knows, they still didn't work!
|
||||
|
||||
We kept feeding more and more time into features that made the emulation so much better, yet this one very popular and very stubborn game would not work.
|
||||
[Subv](https://github.com/Subv/) spent many long hours reverse engineering the game, and found that at the core of the game lay a state machine that drives the game engine.
|
||||
The game would transition from state to state, and, mysteriously, whenever the game softlocked, it simply wasn't moving onto the next state.
|
||||
As cool as it is to learn what causes the softlock, it doesn't answer the big question of *why* the game doesn't transition to the next state like it should.
|
||||
After spending more time than anyone could have asked, eventually he burned out and moved on to develop other amazing features for Citra such as multiplayer network support, leaving us without any more clues to why the game freezes.
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/kirby.png"
|
||||
title="Kirby Battle Royale's missing sounds have been found!"
|
||||
>}}
|
||||
|
||||
## Then Is the Problem Everyone's Best Guess: AAC Audio?
|
||||
|
||||
Well-informed users have pointed out for years that the specific sounds that are not playing in Citra when emulating Pokémon X all have a very suspicious thing in common: all of them are stored in AAC audio format.
|
||||
AAC (or [Advanced Audio Coding](https://en.wikipedia.org/wiki/Advanced_Audio_Coding)) is a standard audio format that typically has better sounding audio than mp3 at the same bitrate.
|
||||
While we appreciate the detective work, there was one glaring problem with deciding that we just needed to add AAC audio support.
|
||||
How *does* one add AAC audio support to Citra's HLE audio?
|
||||
|
||||
The answer was talked about earlier: in order to add a new feature in HLE audio, one needs to reverse engineer the audio code that the games use, and then find out exactly how the audio code processes AAC audio; where the data is passed through, where each decoding option is stored, and all the way down to what every bit of data written to the audio pipe semantically means.
|
||||
To make matters worse, there's no guarantee that this will fix any other games with similar symptoms.
|
||||
After all, a game can upload any code it wants to the audio chip, meaning even if they both used AAC audio, they could potentially use different decoding options, causing the HLE AAC decoder to work for one game and not the other.
|
||||
And worst of all, it's possible that everyone is wrong, and X/Y are freezing because of a completely unrelated issue!
|
||||
|
||||
Faced with this dilemma, [wwylele](https://github.com/wwylele) designed a test to show that audio is likely the cause of the softlock.
|
||||
He knew from the get go that the HLE audio code was based off reverse engineering the most common audio code that games use, the home menu, and decided to make a custom rom hack for Pokémon X that replaced its audio code with the home menu audio.
|
||||
Upon launching the game on a 3DS, everything seemed fine at first, but soon enough the familiar lack of background music kicked in, and Pokémon X started to behave exactly like it does in Citra.
|
||||
One short level up later, and the game froze, just like in Citra!
|
||||
We double-checked the results by recreating this on different copies of Pokémon X and different 3DSes, and it all went the exact same way.
|
||||
Audio issues were very likely the cause, but what then should be the fix?
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/dp.png"
|
||||
title="Detective Pikachu cutscenes no longer skip parts and now run at the proper speed"
|
||||
>}}
|
||||
|
||||
## The Long Road to LLE Audio Emulation
|
||||
|
||||
The methods for fixing any audio issues boil down to two potential solutions.
|
||||
Either take a good amount of time to research, reverse engineer, and recreate the audio code for Pokémon X/Y in HLE, or build out a program that can read the original binary audio code in Pokémon X/Y and emulate the actual audio chip, known as LLE.
|
||||
Both of the options have advantages and disadvantages.
|
||||
HLE means it'll be faster overall to get working, but also will likely take a lot more time and effort to fix bugs in other games with slightly different audio code; whereas with LLE, potentially all audio code in every game will *just work*, but it also will take a lot longer to write, involve even more detailed technical research, and scariest of all, will probably end up running much slower.
|
||||
Weighing the risks and rewards, [wwylele](https://github.com/wwylele) ended up choosing to build out a full LLE audio emulator, what's now known as Teakra.
|
||||
|
||||
The first commit on Teakra started in late January 2018, but the design and research phase started before this.
|
||||
The audio chip in the 3DS, the TeakLite, was a part of the DSi system as well, albeit only used by a very small number of DSiWare titles.
|
||||
In spite of its limited use on the DSi, [GBATek](http://problemkaputt.de/gbatek.htm#dsixpertteakdsp) is loaded with valuable information about the processor, put together by the reverse engineering efforts of Martin Korth and many other contributors.
|
||||
There are others who have worked hard to write documentation, which [wwylele](https://github.com/wwylele) referenced often throughout development.
|
||||
|
||||
Building an LLE audio emulator from scratch is an exciting, yet somewhat scary prospect.
|
||||
When working on HLE audio emulation, you really start to understand what the games are doing, but when writing an LLE audio emulator, you create a magical black box where binary data goes in, and binary data comes out.
|
||||
This was especially true for [wwylele](https://github.com/wwylele) because he had never worked with a DSP before this!
|
||||
It's daunting to know that you'll gain a deep understanding of the architecture and the instruction set of the audio chip, but you won't gain any detailed knowledge of how the audio code is functioning.
|
||||
|
||||
<div style="text-align: center;">
|
||||
<iframe
|
||||
src="https://clips.twitch.tv/embed?clip=CloudySmallAlligatorBIRB&autoplay=false&muted=true"
|
||||
height="300"
|
||||
width="400"
|
||||
scrolling="no"
|
||||
preload="metadata"
|
||||
allowfullscreen="true">
|
||||
</iframe>
|
||||
<h4>Who knew live streaming yourself staring at a monitor for hours could be this fun!</h4>
|
||||
</div>
|
||||
|
||||
## Wait, How Long Until This Starts Playing Sound?
|
||||
|
||||
Several months after starting, the interpreter was coming along nicely, and it was time to start hooking things together.
|
||||
As a quick explanation about what the interpreter is, the interpreter is responsible for running the actual machine code of the audio code, and emulating each of the instructions on the computer that it's running on.
|
||||
This marked another very exciting yet very scary point in time; it had been about 5 months of work on audio emulation, and all of it in complete silence!
|
||||
To understand why, first one must understand that audio hardware is rather complicated, and it's more than just running the machine code.
|
||||
Anything beyond simple audio output is typically generated through specialized hardware known as a [Digital Signal Processor](https://en.wikipedia.org/wiki/Digital_signal_processor), or DSP for short.
|
||||
This custom built hardware is very efficient at transforming and processing audio samples while using less power than the CPU would, enabling the game developers to produce high quality audio without severely impacting battery life.
|
||||
|
||||
In order to start seeing results, [wwylele](https://github.com/wwylele) needed to emulate the ways that the 3DS communicates with the DSP chip, such as [Memory Mapped IO](https://en.wikipedia.org/wiki/Memory-mapped_I/O), [hardware interrupts](https://en.wikipedia.org/wiki/Interrupt), and [Direct Memory Access](https://en.wikipedia.org/wiki/Direct_memory_access).
|
||||
The first two are a piece of cake to recreate compared to DMA.
|
||||
There are straightforward test cases one can write and run on a real 3DS to verify how the 3DS and TeakLite DSP communicate and recreate this in Teakra, and after a month of work, [wwylele](https://github.com/wwylele) got them both functional.
|
||||
But DMA poses a unique challenge, as DMA enables the DSP to do direct memory to memory transfers, independent of what the CPU is doing, making it really hard to figure out how it works!
|
||||
To add to the trouble, DMA is the least documented feature on [GBATek](http://problemkaputt.de/gbatek.htm#dsixpertteakdsp), meaning there is nothing one can study to get an understanding of how the TeakLite does DMA transfers.
|
||||
|
||||
Maybe, just maybe, DMA wouldn't be needed to produce audio output!
|
||||
Around August 2018, [wwylele](https://github.com/wwylele) hooked everything together except for DMA with this hope in mind and...
|
||||
|
||||
Nothing.
|
||||
|
||||
Even worse, the games exhibited the same behavior as before HLE audio was added to Citra, implying that the games weren't detecting that anything was working at all.
|
||||
After spending a few weeks fiddling around with the code, and trying to rule out that it wasn't playing audio because of some bug in the existing code, [wwylele](https://github.com/wwylele) reaffirmed what he always knew.
|
||||
When it comes to writing an LLE DSP emulator, it's all or nothing.
|
||||
Either all of your code works, or absolutely nothing happens.
|
||||
Time to work on DMA.
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/dspnotes.png"
|
||||
title="A small sample of what it looks like when you are trying to understand all of this DSP stuff"
|
||||
>}}
|
||||
|
||||
<h4 style="text-align: center;"><a href="/resources/entry/accurate-audio-emulation/dspnote.pdf">The full notes are uploaded as a pdf in case someone finds this useful.</a></h4>
|
||||
|
||||
## Burnout Strikes
|
||||
|
||||
Over the next month and into September, [wwylele](https://github.com/wwylele) took shots in the dark and tried to implement DMA.
|
||||
He started first with a simple approach to copy data to and from the specific memory regions.
|
||||
DMA allows the DSP to copy data quickly both to and from the 3DS RAM, making it well suited for uploading audio samples and writing audio output.
|
||||
With this simple approach in place, data was being transferred into the emulated DSP, but the output was always zero.
|
||||
Debug the code as he might, it was just too frustrating to figure out what was wrong.
|
||||
Was there an error in the interpreter? MMIO? Audio output? Maybe it was actually in DMA?
|
||||
At this point, the stress was too much to handle.
|
||||
The fear of failure after spending so much time and effort on this project really sunk in, and [wwylele](https://github.com/wwylele) just stopped working on Teakra.
|
||||
By the middle of September, [wwylele](https://github.com/wwylele) had just had enough, and decided to work on something else in the meantime.
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/conversation.png"
|
||||
title="It turns out developers are still just regular human beings. Thankfully everything turned out okay!"
|
||||
>}}
|
||||
|
||||
## Success... Finally!
|
||||
|
||||
The end of November rolls around with no news about DSP LLE, and [wwylele](https://github.com/wwylele) is working tirelessly to fix many other core issues, including [fixing issues with how Citra handled memory that prevented many cheat codes from working properly](https://github.com/citra-emu/citra/pull/4392) (but more on that in another blog post!)
|
||||
Out of nowhere, there's new progress on DMA.
|
||||
[wwylele](https://github.com/wwylele) worked out some extra details about the different patterns that the DMA can use to copy memory, and things started taking off from there.
|
||||
The next day, he noticed an [oversight](https://github.com/wwylele/teakra/commit/d22c2d99d3b0858eb190bf9298815fcac237793a#diff-fe5ba875bf987b9df6685326294fe86fR13) in his simple DMA approach, which ended up causing the DMA to copy data to the *program* region in memory instead of the data region!
|
||||
Now that data was going to the right spot, it was much easier to debug.
|
||||
|
||||
After some more reverse engineering and hardware testing, wwylele had a good idea of how to recreate DMA completely, and tried it out on a custom application that just produces a simple sine wave.
|
||||
|
||||
{{< audio src="/resources/entry/accurate-audio-emulation/sine_wav_deformed.ogg" >}}
|
||||
|
||||
After some more tinkering, and with renewed enthusiasm, he started finding and fixing minor bugs here and there.
|
||||
All of a sudden, everything just started working.
|
||||
|
||||
{{< audio src="/resources/entry/accurate-audio-emulation/kirby_bad.ogg" >}}
|
||||
|
||||
And with a few more fixes...
|
||||
|
||||
{{< audio src="/resources/entry/accurate-audio-emulation/kirby_good.ogg" >}}
|
||||
|
||||
Finally, on Dec 6th, this is what happened after we hooked it into Citra's audio framework (sped up to full speed.)
|
||||
|
||||
{{< audio src="/resources/entry/accurate-audio-emulation/pokemonx.ogg" >}}
|
||||
|
||||
{{< figure src="/images/entry/accurate-audio-emulation/mhgen_najarala_armor_4K.png"
|
||||
title="The audio used to be too loud after changing to certain armor in Monster Hunter Generations, but this bug is no more!"
|
||||
>}}
|
||||
|
||||
## The Future of Audio in Citra
|
||||
|
||||
So what is going to happen to the current audio code?
|
||||
As you can see, there's a lot of benefit in both approaches, and we feel they both have a bright future ahead of them.
|
||||
HLE audio will almost always remain the preferred choice for users, as it's much faster and produces very good audio quality, while LLE audio will be an excellent tool for finding and debugging audio issues, as after any last remaining bugs are worked out, it should have near perfect compatibility.
|
||||
With LLE audio released now, we can use it to take a deeper look at the communication between 3DS and DSP, allowing us to mimic responses from the DSP, and begin researching what each of the bytes of data actually mean.
|
||||
We plan to fix any outstanding issues with HLE "fast" audio to support all of the games, and also plan to optimize LLE "accurate" audio so it will be usable at a good framerate!
|
||||
|
||||
|
||||
<h4 style="text-align:center;">
|
||||
Thanks to our Patreon supporters, our fans, and our userbase for the continual support!
|
||||
|
||||
<b>Please consider supporting us on [Patreon](https://www.patreon.com/citraemu)!<br>
|
||||
If you would like to contribute to this project, checkout our [GitHub](https://github.com/citra-emu/citra)!</b>
|
||||
</h4>
|
|
@ -7,17 +7,23 @@ coauthor = "jroweboy"
|
|||
forum = 42
|
||||
+++
|
||||
|
||||
Sometimes it's hard to wait. We've noticed that users are very excited about the future of Citra, which means wanting to try all of the changes all of the time.
|
||||
But, emulator development can be a slow, arduous process as new changes can bring big regressions and problems with the much wanted new features.
|
||||
Sometimes it's hard to wait. We've noticed that users are very excited about the future of Citra, which means wanting
|
||||
to try all of the changes all of the time.
|
||||
But, emulator development can be a slow, arduous process as new changes can bring big regressions and problems with
|
||||
the much wanted new features.
|
||||
|
||||
In order to satiate the needs of our users, we'll be adding new builds for download: bleeding edge builds!
|
||||
These builds will contain experimental features and changes designed to give the absolute fastest builds with the most features combined into one download!
|
||||
Since these releases are official, unlike other random builds you might find on the internet, there is no chance that they will contain a virus, or anything else that can potentially be harmful.
|
||||
These builds will contain experimental features and changes designed to give the absolute fastest builds with the most
|
||||
features combined into one download!
|
||||
Since these releases are official, unlike other random builds you might find on the internet, there is no chance that
|
||||
they will contain a virus, or anything else that can potentially be harmful.
|
||||
|
||||
Because updates will come at a rapid pace and there is a chance of these changes adversely affecting emulation, the builds will let you know when a newer version is available and **auto-update** if you allow it.
|
||||
Because updates will come at a rapid pace and there is a chance of these changes adversely affecting emulation, the
|
||||
builds will let you know when a newer version is available and **auto-update** if you allow it.
|
||||
|
||||
You can download the bleeding edge development builds at our <a href="https://citra-emu.org/download/">downloads page</a> right now!
|
||||
You can download the bleeding edge development builds at our [downloads page](https://citra-emu.org/download/) right now!
|
||||
While Windows is the only operating system targeted at this time, the other operating systems will follow shortly.
|
||||
|
||||
While these builds aren't technically supported, they can be extremely useful for catching regressions and other issues from the various experimental features rolled into them.
|
||||
While these builds aren't technically supported, they can be extremely useful for catching regressions and other issues
|
||||
from the various experimental features rolled into them.
|
||||
If you experience a bug, please make sure that the latest nightly builds do not have the issue before reporting it.
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
+++
|
||||
date = "2017-11-04T07:17:00-04:00"
|
||||
title = "Announcing Networking Support"
|
||||
tags = [ "feature-update" ]
|
||||
author = "jmc47"
|
||||
forum = 4744
|
||||
+++
|
||||
|
||||
_Networked Multiplayer_ is one of those features that was so surprising to see, that the lucky few chosen to test it were wondering if it was real. For the past year, several developers have banded together to bring this amazing implementation of online play to Citra.
|
||||
|
||||
<div style="position:relative;height:0;padding-bottom:65%"><iframe src="https://www.youtube.com/embed/z_Nni6NZoy0?ecevr=2" style="position:absolute;width:100%;height:100%;left:0" width="641" height="360" frameborder="0" allowfullscreen></iframe></div>
|
||||
|
||||
The Nintendo 3DS heavily relies on wireless for its slew of multiplayer compatible titles. Considering that so many games feel empty without their multiplayer features, we're excited to announce that in select titles, you'll be able to play together with your friends across the world in the latest Canary builds of Citra!
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/LetsBattle.png"
|
||||
title="Let's Battle!" >}}
|
||||
|
||||
#### Bringing Multiplayer to Citra
|
||||
|
||||
Emulating 3DS local wireless and bringing it to Citra was a huge endeavor shared by [subv](https://github.com/Subv), [B3N30](https://github.com/B3n30), [jroweboy](https://github.com/jroweboy), and [JayFoxRox](https://github.com/JayFoxRox). It went through several stages of development, from actually reverse-engineering how wireless worked in games, to implementing those features in Citra, and then implementing an infrastructure so that even casual users could easily take advantage of this feature.
|
||||
|
||||
This emulates the 3DS' ability to do *local wireless* multiplayer. As such, it doesn't rely on Nintendo's server and does not require a Nintendo Network ID. While on a real 3DS you'd be limited to the people in your immediate vicinity, Citra boasts a complex server/client infrastructure that forwards a game's wireless communication across the internet.
|
||||
|
||||
Unlike single console netplay used in most emulators, users won't have to worry about desyncs, synchronizing saves, or any other issues typical of netplay. Each user is using their instance of Citra as a unique emulated 3DS that is communicating with everyone else through that particular server.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/GameBrowser.png"
|
||||
title="Join your friends!" >}}
|
||||
|
||||
Currently, servers created in Citra can hold up to 16 players. High player counts should be avoided for now due to bandwidth issues. In this initial release, each connected Citra instance sends raw packets to the host (or server) and the server then forwards those packets to every single client. As such, with each player added, the bandwidth requirements increase greatly.
|
||||
|
||||
While hundreds of games support wireless connectivity, compatibility is limited in the initial release. Tons of titles were tested, but only a handful came up as working properly. Note games may handle latency differently and your experience may vary.
|
||||
|
||||
### The Server Browser
|
||||
|
||||
In order to get together with other players, you're going to have to join the same room with Citra's server browser. Creating and joining servers is extremely easy in Citra and can be done in just a few clicks. If you're a verified user, you can create a public game through the traversal server for people to join. These public games can be seen by **anyone** on the server browser, but you are also able to put a password on publicly listed games. **Remember to port forward, otherwise your friends won't be able to connect!**
|
||||
|
||||
Unverified users aren't left without options, though - they still have the ability to create unlisted games, direct connecting, and can join any hosted server.
|
||||
|
||||
Do note that verified users **will** have their privileges revoked for violating any site policies while on the server chatroom. Please respect the *recommended game* listed in publicly hosted games, as even unrelated games will add to the bandwidth load.
|
||||
|
||||
### Wireless Compatibility
|
||||
#### Works Like a Charm
|
||||
##### Super Smash Bros. for 3DS
|
||||
|
||||
_Super Smash Brother's_ local wireless play works perfectly in Citra for up to four players. Because the game expects all players to be running in lockstep, users will need to maintain similar framerates for a stable connection. Some stages, such as the pictochat stage, can run full speed even on moderately powerful computers.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/SmashLocal.png"
|
||||
title="1v1 me fox only no items final destination" >}}
|
||||
|
||||
##### Pokémon X/Y, Pokémon Omega Ruby/Alpha Sapphire, and Pokémon Sun/Moon
|
||||
|
||||
Almost everything works perfectly in the _Pokémon_ games. The only thing that fails is adding friends - so try to stay away from that. Users can battle, trade, and watch passerbys as they show up or leave on the local wireless server.
|
||||
|
||||
Because of compatibility issues in general with X and Y, using wireless support may be problematic for those two titles.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/ChallengePok.png"
|
||||
title="Challenge your friends in beautifully upscaled Pokémon battles!" >}}
|
||||
|
||||
##### New Super Mario Bros. 2
|
||||
|
||||
_New Super Mario Bros. 2_ runs perfectly, and our testers were able to play together multiple worlds into the game flawlessly. Users on the same server can search for partners and join up just fine.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/NSMB2.jpg"
|
||||
title="Your princess is in another castle? Save her together!" >}}
|
||||
|
||||
#### Functional But Flawed
|
||||
|
||||
##### Luigi's Mansion: Dark Moon
|
||||
|
||||
This title has perfectly functional wireless support for trying to tackle the "Scarescraper"! Unfortunately, the game is so demanding that getting a fun experience out of it is near impossible.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/LuigisMansionLobby.png"
|
||||
title="Happy Hallowe- oh, it's November. Whatever, Luigi doesn't care!" >}}
|
||||
|
||||
##### Monster Hunter 3U and 4U
|
||||
|
||||
The _Monster Hunter_ games are extremely demanding in Citra, but wireless support _does_ somewhat work. A second player can join a game, share quests and trade guild cards. But, the game supports up to four local players on console, and anything more than two causes disconnections in Citra.
|
||||
|
||||
{{< figure src="/images/entry/announcing-networking-support/image.png"
|
||||
title="Go out and hunt with all your friends! ... as long as that number is only 2." >}}
|
||||
|
||||
#### Incompatible
|
||||
|
||||
For various reasons, the following games were tested and do not work. Also note that Download Play and Spotpass titles do not work due to limitations in what Citra currently emulates.
|
||||
|
||||
* Mario Party Island Tour
|
||||
* Mario Party Star Rush
|
||||
* The Legend of Zelda: TriForce Heroes
|
||||
* Mario Kart 7
|
||||
* Tetris Ultimate
|
||||
* Code of Princess
|
||||
* Sonic Generations
|
||||
* Asphalt Assault 3D
|
||||
* Ridge Racer 3D
|
||||
* Monster Hunter Generations
|
||||
* Monster Hunter X
|
||||
* Monster Hunter XX
|
||||
* Street Fighter IV
|
||||
* Kirby Triple Deluxe
|
||||
* Dragon Quest Monsters: Terry's Wonderland 3D
|
||||
* Resident Evil: The Mercenaries 3D
|
||||
* Dragon Quest Monsters: Joker 3 Professional
|
||||
* F1 2011
|
||||
* Kirby Fighters Deluxe
|
||||
* Planet Crashers
|
||||
|
||||
### Going Forward
|
||||
|
||||
After the months of work put into making _Networked Multiplayer_ a reality, we're excited to see it finally brought into the public eye. While only a handful of games work in this initial release, we're hoping to bring support to more titles in the future, as well as optimizing the netcode for lower bandwidth usage, and allowing for even bigger user hosted servers.
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
+++
|
||||
date = "2018-07-06T22:45:00+05:30"
|
||||
title = "Citra Now Has a Patreon"
|
||||
tags = [ "citra-release" ]
|
||||
author = "bunnei"
|
||||
forum = 31894
|
||||
+++
|
||||
|
||||
It's finally happening folks: The Citra Team would like to announce that we now have a project-wide Patreon. This will be a way for you, our users, to donate directly to the Citra developers, in support of their efforts to continue to make Citra the best option available to enjoy 3DS games. Patreon will be yet another way for our biggest fans to contribute to the project.
|
||||
|
||||
<h3 align="center">
|
||||
<b><a href="https://www.patreon.com/citraemu">Become a Patron !</a></b>
|
||||
</h3>
|
||||
|
||||
## Why start a Patreon now?
|
||||
|
||||
This is something that has been requested by users for several years now. However, the Citra Team has been a bit apprehensive. In the past, we have had some concerns about how a Patreon might be distributed among the developers. We've also been concerned that the idea of profiting from emulation may taint the free and open source spirit of Citra. We would like to be crystal clear: Citra will always be free and completely open source, and we have no plans to use Patreon to put our project behind any form of paywall.
|
||||
|
||||
However, there have been a few emulator teams that have had very successful Patreons in recent years, and users have seen these projects make tremendous progress. Naturally, many such users have asked the question, "How much further progress could Citra make if they had a Patreon?"
|
||||
|
||||
While we do not know the exact answer to this question, after some careful consideration, we've decided that a Patreon is a good move for Citra. Our developers dedicate hundreds (and sometimes thousands) of hours to the project purely out of passion for emulation and software development. However, this is not sustainable, as our developers also have to balance time between real life, work and school. We, as a team, believe that having a Patreon will both motivate (and eventually enable) our developers to work even harder on Citra.
|
||||
|
||||
We believe that we've come up with a plan to fairly share the Patreon among the core members of our team. Furthermore, as a team, we are all firm in our commitment to ensure that Patreon will only be used to incentivize open source development, and not to charge users for Citra.
|
||||
|
||||
## How will Citra's Patreon work?
|
||||
|
||||
Citra will have a project-wide Patreon – there will be a single way to donate and contribute to the entire team. Donations to this Patreon will be shared evenly among the core members of the Citra Team (this includes developers, but also may include our most active administrators and writers). Core membership will be established based on a combination of tenure and activity. We want to ensure that our long time contributors are rewarded, but also that there is room for our newer "heavy-hitting" developers to be part of this.
|
||||
|
||||
**Thanks for reading, and we hope that you support us in this endeavor!**
|
|
@ -6,15 +6,38 @@ author = "bunnei"
|
|||
forum = 33
|
||||
+++
|
||||
|
||||
While Citra was first founded in April of 2014, visible progress for the emulator didn't really happen until the turn of the year. After a long struggle to get anything to boot, 2015 saw Citra evolve from an experimental emulator that couldn't run games into an experimental emulator that can run games. And while it may not seem like Citra is that far along, it is truly amazing how much things have progressed in just a year since the first commercial title booted.
|
||||
While Citra was first founded in April of 2014, visible progress for the emulator didn't really happen until the turn
|
||||
of the year. After a long struggle to get anything to boot, 2015 saw Citra evolve from an experimental emulator that
|
||||
couldn't run games into an experimental emulator that can run games. And while it may not seem like Citra is that far
|
||||
along, it is truly amazing how much things have progressed in just a year since the first commercial title booted.
|
||||
|
||||
However, with Citra's success and high visibility within the emulation community, it may be easy to think that we've gotten this far on our own, but that would be quite misguided. Citra would not exist without the work that others have done before and alongside it: Particularly the folks behind [3dmoo](https://github.com/plutooo/3dmoo/) ([Normmatt](http://github.com/normmatt), [ichfly](http://github.com/ichfly), and [plutoo](https://github.com/plutooo)), who did a lot of the early reverse-engineering to boot commercial games; as well as those who have worked tirelessly to break open the 3DS and [share their work](https://www.3dbrew.org/wiki/Main_Page) publically ([yellows8](https://github.com/yellows8), [Bond697](https://github.com/bond697), [fincs](https://github.com/fincs), among many others), and [smea](https://github.com/smealum) for providing a public [way to run](http://smealum.net/ninjhax/) (and a [library](https://github.com/smealum/ctrulib) to create) homebrew. We've been lucky to be part of a much larger community of hackers, developers and researchers that have always been willing to lend a hand in some way, which is something that many other emulator teams are not quite as fortunate to have!
|
||||
However, with Citra's success and high visibility within the emulation community, it may be easy to think that we've
|
||||
gotten this far on our own, but that would be quite misguided. Citra would not exist without the work that others
|
||||
have done before and alongside it: Particularly the folks behind [3dmoo](https://github.com/plutooo/3dmoo/)
|
||||
([Normmatt](http://github.com/normmatt), [ichfly](http://github.com/ichfly), and [plutoo](https://github.com/plutooo)),
|
||||
who did a lot of the early reverse-engineering to boot commercial games; as well as those who have worked tirelessly
|
||||
to break open the 3DS and [share their work](https://www.3dbrew.org/wiki/Main_Page) publically
|
||||
([yellows8](https://github.com/yellows8), [Bond697](https://github.com/bond697),
|
||||
[fincs](https://github.com/fincs), among many others), and [smea](https://github.com/smealum) for providing a public
|
||||
[way to run](http://smealum.net/ninjhax/) (and a [library](https://github.com/smealum/ctrulib) to create) homebrew.
|
||||
We've been lucky to be part of a much larger community of hackers, developers and researchers that have always been
|
||||
willing to lend a hand in some way, which is something that many other emulator teams are not quite as fortunate
|
||||
to have!
|
||||
|
||||
Like most young projects, Citra didn't have a great website infrastructure featuring a blog last year; there was no need to as it didn't boot games or have a big fanbase interested in its development. It was just one of several emulators that had promise. With that promise starting to be fulfilled and a shiny new blog ready and waiting, let us look back at the year that Citra rose above the rest and became **THE** 3DS emulator.
|
||||
Like most young projects, Citra didn't have a great website infrastructure featuring a blog last year; there was no
|
||||
need to as it didn't boot games or have a big fanbase interested in its development. It was just one of several
|
||||
emulators that had promise. With that promise starting to be fulfilled and a shiny new blog ready and waiting, let us
|
||||
look back at the year that Citra rose above the rest and became **THE** 3DS emulator.
|
||||
|
||||
## Winter: The First Retail Games
|
||||
|
||||
In late 2014, Citra was a very small project developed primarily by [bunnei](https://github.com/bunnei) and [neobrain](http://github.com/neobrain). The heart and soul behind the effort to get a game rendering was their reverse-engineering skills put into figuring out how the 3DS GPU worked and accurately represented it in an accuracy focused software renderer. Meanwhile, [bunnei](https://github.com/bunnei) assisted with that while figuring out how to recreate the environment that the 3DS games run in, with a particular focus on emulating the 3DS' operating system. Because they focused on accurate emulation, parts of the emulator were fairly advanced despite no commercial games booting.
|
||||
In late 2014, Citra was a very small project developed primarily by [bunnei](https://github.com/bunnei) and
|
||||
[neobrain](http://github.com/neobrain). The heart and soul behind the effort to get a game rendering was their
|
||||
reverse-engineering skills put into figuring out how the 3DS GPU worked and accurately represented it in an accuracy
|
||||
focused software renderer. Meanwhile, [bunnei](https://github.com/bunnei) assisted with that while figuring out how
|
||||
to recreate the environment that the 3DS games run in, with a particular focus on emulating the 3DS' operating system.
|
||||
Because they focused on accurate emulation, parts of the emulator were fairly advanced despite no commercial games
|
||||
booting.
|
||||
|
||||
Until one day...
|
||||
<br></br>
|
||||
|
@ -22,18 +45,45 @@ Until one day...
|
|||
{{< img src="entry/citra-progress-report-2015-p1/image01.png" center="true" >}}
|
||||
|
||||
<br></br>
|
||||
Recognize the game? That's The Legend of Zelda: Ocarina of Time 3D rendering on Citra on [December 13, 2014](https://twitter.com/fail_cluez/status/543796766270046210). This distorted upside-down Triforce loading icon was the first rendering of a commercial title in Citra. After that, Ocarina of Time 3D would promptly hang, but even this little blip caused excitement from the developers. To get a retail game to show any graphics at all – be it a simple icon or a complex 3D scene – requires that a virtual environment be created that is sufficiently complete such that from the perspective of a game, it is running on an actual Nintendo 3DS. This isn’t just a matter of being able to execute the game’s native machine code, but also provide it with enough of the essential features it expects when running on a real 3DS. For example, 3DS games run within a full operating system (much like your PC or smart phone), that of which Citra needed to duplicate.
|
||||
Recognize the game? That's The Legend of Zelda: Ocarina of Time 3D rendering on Citra on
|
||||
[December 13, 2014](https://twitter.com/fail_cluez/status/543796766270046210). This distorted upside-down Triforce
|
||||
loading icon was the first rendering of a commercial title in Citra. After that, Ocarina of Time 3D would promptly
|
||||
hang, but even this little blip caused excitement from the developers. To get a retail game to show any graphics at
|
||||
all – be it a simple icon or a complex 3D scene – requires that a virtual environment be created that is sufficiently
|
||||
complete such that from the perspective of a game, it is running on an actual Nintendo 3DS. This isn’t just a matter
|
||||
of being able to execute the game’s native machine code, but also provide it with enough of the essential features it
|
||||
expects when running on a real 3DS. For example, 3DS games run within a full operating system (much like your PC or
|
||||
smart phone), that of which Citra needed to duplicate.
|
||||
|
||||
Propelled by this breakthrough, [neobrain](http://github.com/neobrain) and [bunnei](https://github.com/bunnei) worked tirelessly day and night to push Ocarina of Time just a little bit further. With [bunnei](https://github.com/bunnei) focused on fixing core emulation bugs and implementing necessary OS features, [neobrain](http://github.com/neobrain) continued with GPU reverse-engineering based on the features that Ocarina of Time was lacking within the software renderer. While it took months to get the game booting, getting it to the title screen only took a few more days. The result of this hard work may look like nothing but a screenshot from a glitchy emulator, but when it happened it was a huge cause for celebration: Citra's first fully 3D-rendered scene. <br></br>
|
||||
Propelled by this breakthrough, [neobrain](http://github.com/neobrain) and [bunnei](https://github.com/bunnei) worked
|
||||
tirelessly day and night to push Ocarina of Time just a little bit further. With [bunnei](https://github.com/bunnei)
|
||||
focused on fixing core emulation bugs and implementing necessary OS features, [neobrain](http://github.com/neobrain)
|
||||
continued with GPU reverse-engineering based on the features that Ocarina of Time was lacking within the software
|
||||
renderer. While it took months to get the game booting, getting it to the title screen only took a few more days. The
|
||||
result of this hard work may look like nothing but a screenshot from a glitchy emulator, but when it happened it was a
|
||||
huge cause for celebration: Citra's first fully 3D-rendered scene.
|
||||
<br></br>
|
||||
|
||||
{{< img src="entry/citra-progress-report-2015-p1/image03.png" center="true" >}}
|
||||
<br></br>
|
||||
|
||||
This breakthrough only motivated developers further. With a 3D rendered scene under its belt, users had taken notice and news of Citra had spread. This fervor was met with more than just hype, but also results. It was only a matter of weeks before several more retail games were booting in Citra, some of which were able to be played in-game. It became a sort of friendly competition among the developers to see who could be the first to get a new game booting it. Among the next few games to fall were Cave Story and Cave Story 3D, VVVVVV, Ikachan, Gunman Clive, Super Little Acorns, and Retro City Rampage. <br></br>
|
||||
This breakthrough only motivated developers further. With a 3D rendered scene under its belt, users had taken notice
|
||||
and news of Citra had spread. This fervor was met with more than just hype, but also results. It was only a matter of
|
||||
weeks before several more retail games were booting in Citra, some of which were able to be played in-game. It became
|
||||
a sort of friendly competition among the developers to see who could be the first to get a new game booting it. Among
|
||||
the next few games to fall were Cave Story and Cave Story 3D, VVVVVV, Ikachan, Gunman Clive, Super Little Acorns, and
|
||||
Retro City Rampage.
|
||||
<br></br>
|
||||
|
||||
{{< youtube ZGQWVMCdfK0 >}}
|
||||
<br></br>
|
||||
|
||||
While this was cause for excitement, there is a pattern to be noticed in the games that booted. Most of the titles were either simple 2D games, or ports from other systems. This actually has some meaning: ports and simple games are less likely to use new features of a system than say a blockbuster title from Nintendo designed for the system to show off what it can really do.
|
||||
While this was cause for excitement, there is a pattern to be noticed in the games that booted. Most of the titles were
|
||||
either simple 2D games, or ports from other systems. This actually has some meaning: ports and simple games are less
|
||||
likely to use new features of a system than say a blockbuster title from Nintendo designed for the system to show off
|
||||
what it can really do.
|
||||
|
||||
In the [next part](https://citra-emu.org/entry/citra-progress-report-2015-p2), we'll continue our 2015 retrospective with Spring. By then, Citra fever was in full effect, with new devs and old faces showing up to throw their hat in the ring and see who could make the next big breakthrough. No one was ready for how much could change in just three more months.
|
||||
In the [next part](https://citra-emu.org/entry/citra-progress-report-2015-p2), we'll continue our 2015 retrospective
|
||||
with Spring. By then, Citra fever was in full effect, with new devs and old faces showing up to throw their hat in the
|
||||
ring and see who could make the next big breakthrough. No one was ready for how much could change in just three more
|
||||
months.
|
||||
|
|
|
@ -6,26 +6,49 @@ author = "bunnei"
|
|||
forum = 36
|
||||
+++
|
||||
|
||||
This month we bring you the second installment of our two-part progress report on Citra in 2015! With this part, we discuss the evolution from Citra being able to barely run a few commercial games at a few frames-per-second, to where it is in 2016: Running many retail games at reasonable speeds, some of which are fully playable with near flawless graphics! We discuss Citra's new "dyncom" CPU core, the OpenGL renderer, per-pixel lighting, and various bug fixes. Lastly, we wrap up with an outlook for 2016, and a special thanks to everyone who has helped make Citra what it is today!
|
||||
This month we bring you the second installment of our two-part progress report on Citra in 2015! With this part, we
|
||||
discuss the evolution from Citra being able to barely run a few commercial games at a few frames-per-second, to where
|
||||
it is in 2016: Running many retail games at reasonable speeds, some of which are fully playable with near flawless
|
||||
graphics! We discuss Citra's new "dyncom" CPU core, the OpenGL renderer, per-pixel lighting, and various bug fixes.
|
||||
Lastly, we wrap up with an outlook for 2016, and a special thanks to everyone who has helped make Citra what it is
|
||||
today!
|
||||
|
||||
## Spring 2015: A New CPU, Renderer and More
|
||||
|
||||
The arms race to get games booting ran into a wall. Often, testing games and getting to crash points would be incredibly painful because of how slow the emulator ran. Instead of measuring frames-per-second, testers often referred to seconds-per-frame. Donkey Kong Country Returns 3D would sometimes require three realtime seconds to render a single in-game frame in the software renderer! It took over 90 minutes to capture all of the footage for a three minute video of Super Monkey Ball 3D! <br></br>
|
||||
The arms race to get games booting ran into a wall. Often, testing games and getting to crash points would be incredibly
|
||||
painful because of how slow the emulator ran. Instead of measuring frames-per-second, testers often referred to
|
||||
seconds-per-frame. Donkey Kong Country Returns 3D would sometimes require three realtime seconds to render a single
|
||||
in-game frame in the software renderer! It took over 90 minutes to capture all of the footage for a three minute video
|
||||
of Super Monkey Ball 3D!
|
||||
|
||||
{{< youtube t0TGSeQe1wE >}}
|
||||
{{< youtube t0TGSeQe1wE >}}
|
||||
|
||||
<br></br>
|
||||
Within the next few months, [bunnei](https://github.com/bunnei) and [Lioncash](https://github.com/lioncash) replaced the old "ARMULATOR" CPU core in Citra with a better implementation that was both several times faster and much more accurate. Despite the fact that it was still an interpreter, this new core was still efficient enough that the performance implications were huge. With this new core, games that were light on graphics could reach above half-speed on very strong processors.
|
||||
Within the next few months, [bunnei](https://github.com/bunnei) and [Lioncash](https://github.com/lioncash) replaced
|
||||
the old "ARMULATOR" CPU core in Citra with a better implementation that was both several times faster and much more
|
||||
accurate. Despite the fact that it was still an interpreter, this new core was still efficient enough that the
|
||||
performance implications were huge. With this new core, games that were light on graphics could reach above half-speed
|
||||
on very strong processors.
|
||||
|
||||
Shortly thereafter, a new developer joined the Citra team – [tfarley](https://github.com/tfarley) – with the ambitious goal of implementing a hardware renderer using OpenGL. Up until this point, Citra had used a software renderer primarily developed by [neobrain](http://github.com/neobrain) to render graphics. While a software renderer is great for development and achieving pixel-perfect accuracy, Citra’s GPU emulation had become the major performance bottleneck. Even with infinitely fast CPU emulation, the software renderer was so slow that no games would run full speed despite this.
|
||||
Shortly thereafter, a new developer joined the Citra team – [tfarley](https://github.com/tfarley) – with the ambitious
|
||||
goal of implementing a hardware renderer using OpenGL. Up until this point, Citra had used a software renderer
|
||||
primarily developed by [neobrain](http://github.com/neobrain) to render graphics. While a software renderer is great
|
||||
for development and achieving pixel-perfect accuracy, Citra’s GPU emulation had become the major performance
|
||||
bottleneck. Even with infinitely fast CPU emulation, the software renderer was so slow that no games would run full
|
||||
speed despite this.
|
||||
|
||||
While the rest of the team continued with other development efforts, [tfarley](https://github.com/tfarley) went on a month-long battle developing this new OpenGL renderer. All of this resulted in Ocarina of Time 3D running nearly perfect in Citra using OpenGL while running at a fairly decent speed! Below is a very early video of Ocarina of Time, before the renderer was completed and merged into CItra's mainline repository. <br></br>
|
||||
While the rest of the team continued with other development efforts, [tfarley](https://github.com/tfarley) went on a
|
||||
month-long battle developing this new OpenGL renderer. All of this resulted in Ocarina of Time 3D running nearly
|
||||
perfect in Citra using OpenGL while running at a fairly decent speed! Below is a very early video of Ocarina of Time,
|
||||
before the renderer was completed and merged into CItra's mainline repository.
|
||||
|
||||
{{< youtube Hj8sPsB5qXQ >}}
|
||||
|
||||
## Summer: More Accuracy, More Performance
|
||||
|
||||
With the summer, development slowed down a bit – but several additional improvements were made. By this point, the team had already made lots of incremental advances in 3DS emulation, resulting in a significant number of retail games booting, such as Super Mario 3D Land, Fire Emblem: Awakening, The Legend of Zelda: A Link Between Worlds, Mario Kart 7, and many more. <br></br>
|
||||
With the summer, development slowed down a bit – but several additional improvements were made. By this point, the
|
||||
team had already made lots of incremental advances in 3DS emulation, resulting in a significant number of retail games
|
||||
booting, such as Super Mario 3D Land, Fire Emblem: Awakening, The Legend of Zelda: A Link Between Worlds, Mario Kart 7,
|
||||
and many more.
|
||||
|
||||
{{< img src="entry/citra-progress-report-2015-p2/earlyunknown1.png" center="true" >}}
|
||||
|
||||
|
@ -48,57 +71,112 @@ forum = 36
|
|||
{{< img src="entry/citra-progress-report-2015-p2/earlyfireemblem.png" center="true" >}}
|
||||
|
||||
<br></br>
|
||||
But there was still one major issue that was blocking many games: video playback. 3DS games use a proprietary format known as “MOFLEX” to play video clips, which are commonly used for intro logos, cut scenes, and more. Not only was the video format unknown, but any time a MOFLEX video was used, Citra would hang in an infinite loop for unknown reasons. However, this issue proved to be no match for our team – within a matter of weeks, Citra developers [yuriks](https://github.com/yuriks) and [Subv](https://github.com/Subv) reverse-engineered and implemented all of the mechanisms necessary to prevent hanging and play MOFLEX videos!<br></br>
|
||||
But there was still one major issue that was blocking many games: video playback. 3DS games use a proprietary format
|
||||
known as “MOFLEX” to play video clips, which are commonly used for intro logos, cut scenes, and more. Not only was the
|
||||
video format unknown, but any time a MOFLEX video was used, Citra would hang in an infinite loop for unknown reasons.
|
||||
However, this issue proved to be no match for our team – within a matter of weeks, Citra developers
|
||||
[yuriks](https://github.com/yuriks) and [Subv](https://github.com/Subv) reverse-engineered and implemented all of the
|
||||
mechanisms necessary to prevent hanging and play MOFLEX videos!<br></br>
|
||||
|
||||
{{< img src="entry/citra-progress-report-2015-p2/3.png" center="true" >}}
|
||||
<p style="text-align: center;">Bravely Default's intro sequence relies on MOFLEX video support <br></br>
|
||||
{{< figure src="/images/entry/citra-progress-report-2015-p2/3.png"
|
||||
alt="Bravely Default"
|
||||
title="Bravely Default's intro sequence relies on MOFLEX video support" >}}
|
||||
|
||||
With many games now running stable with fairly accurate rendering, it became evident that with a bit more speed some titles would not only be playable in Citra, but enjoyable to play. On top of this, more speed would make testing even easier, so with a huge library of games now working, the task again came to making things faster.
|
||||
With many games now running stable with fairly accurate rendering, it became evident that with a bit more speed some
|
||||
titles would not only be playable in Citra, but enjoyable to play. On top of this, more speed would make testing even
|
||||
easier, so with a huge library of games now working, the task again came to making things faster.
|
||||
|
||||
The cause of the slowdown was very obvious: Citra’s emulation of 3DS vertex shaders. With emulators like Dolphin and PPSSPP, your GPU uses shaders to emulate the target system’s GPU, which does not actually use any shaders of its own. The 3DS, on the other hand, has a more modern GPU that natively supports its own shaders – which are not as trivial to emulate in the same manner. The approach that we took was similar to CPU emulation – and we were using a pure interpreter for the job. As such, the solution was pretty obvious; Even a naively implemented Just-In-Time (JIT) compiler would make our shader emulation scream. With that in mind, [bunnei](https://github.com/bunnei) set out to implement a vertex shader JIT.
|
||||
The cause of the slowdown was very obvious: Citra’s emulation of 3DS vertex shaders. With emulators like Dolphin and
|
||||
PPSSPP, your GPU uses shaders to emulate the target system’s GPU, which does not actually use any shaders of its own.
|
||||
The 3DS, on the other hand, has a more modern GPU that natively supports its own shaders – which are not as trivial to
|
||||
emulate in the same manner. The approach that we took was similar to CPU emulation – and we were using a pure
|
||||
interpreter for the job. As such, the solution was pretty obvious; Even a naively implemented Just-In-Time (JIT)
|
||||
compiler would make our shader emulation scream. With that in mind, [bunnei](https://github.com/bunnei) set out to
|
||||
implement a vertex shader JIT.
|
||||
|
||||
While it took several weeks to develop, the difference in speed was very obvious. Vertex heavy games were sometimes two or three times as fast, allowing some games like Ocarina of Time 3D to near full speed in many areas! <br></br>
|
||||
While it took several weeks to develop, the difference in speed was very obvious. Vertex heavy games were sometimes two
|
||||
or three times as fast, allowing some games like Ocarina of Time 3D to near full speed in many areas!
|
||||
|
||||
{{< youtube yhLEs4yEmlU >}}
|
||||
|
||||
## Autumn: Closing out the Year with a Bang!
|
||||
|
||||
After a brief summer hiatus, development on Citra began to pick up again with autumn 2015. While Citra now had a library of games running without severe problems, many still relied on more advanced graphics features that had yet to be reverse-engineered. One of these more widely used features is fragment lighting – a feature that enables complex lighting calculations to be performed on a per-pixel basis. A major breakthrough was made when hacker and homebrew developer fincs made major strides in figuring out the 3DS fragment lighting implementation. Immediately, [bunnei](https://github.com/bunnei) began embodying this work into Citra. <br></br>
|
||||
After a brief summer hiatus, development on Citra began to pick up again with autumn 2015. While Citra now had a
|
||||
library of games running without severe problems, many still relied on more advanced graphics features that had yet
|
||||
to be reverse-engineered. One of these more widely used features is fragment lighting – a feature that enables complex
|
||||
lighting calculations to be performed on a per-pixel basis. A major breakthrough was made when hacker and homebrew
|
||||
developer fincs made major strides in figuring out the 3DS fragment lighting implementation. Immediately,
|
||||
[bunnei](https://github.com/bunnei) began embodying this work into Citra.
|
||||
|
||||
{{< img src="entry/citra-progress-report-2015-p2/rotatecube.gif" center="true" >}}
|
||||
<p style="text-align: center;"> An early fragment lighting demo running in Citra <br></br>
|
||||
{{< figure src="/images/entry/citra-progress-report-2015-p2/rotatecube.gif"
|
||||
alt="Fragment shader test"
|
||||
title="An early fragment lighting demo running in Citra" >}}
|
||||
|
||||
Despite that it’s not a fully complete implementation of fragment lighting, the results have significantly improved Citra’s visuals!
|
||||
Despite that it’s not a fully complete implementation of fragment lighting, the results have significantly improved
|
||||
Citra’s visuals!
|
||||
|
||||
<div class="row" style="margin-top:3em; margin-bottom:1em;">
|
||||
<div class="col-xs-12 col-sm-6" style="text-align:center; margin-bottom: 1em;"><img alt="" src="/images/entry/citra-progress-report-2015-p2/moonbefore.png" style="max-width: 100%; border-style: none; margin-bottom: 1em;" />
|
||||
It's a super moon!
|
||||
</div>
|
||||
{{< figure src="/images/entry/citra-progress-report-2015-p2/moonbefore.png"
|
||||
title="It's a super moon!" >}}
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2015-p2/moonafter.png"
|
||||
title="With fragment lighting implemented, the moon became even scarier! H-hurray?" >}}
|
||||
|
||||
<div class="col-xs-12 col-sm-6" style="text-align:center; margin-bottom: 1em;"><img alt="" src="/images/entry/citra-progress-report-2015-p2/moonafter.png" style="max-width: 100%; border-style: none; margin-bottom: 1em;" />
|
||||
With fragment lighting implemented, the moon became even scarier! H-hurray?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
While no more major features were merged into Citra by the turn of the year, [Subv](https://github.com/Subv) came up with one final teaser of things to come before letting 2015 come to a close. CROs, the dynamically linked libraries of the 3DS (similiar to DLLs on Windows), blocked several very popular 3DS games from booting in Citra, such as Pokemon X, Y, Omega Ruby, Alpha Sapphire and Super Smash Bros. for 3DS. While the implementation was far from done, it still was able to boot up some of the games that relied heavily on this feature.
|
||||
<br></br>
|
||||
While no more major features were merged into Citra by the turn of the year, [Subv](https://github.com/Subv) came up
|
||||
with one final teaser of things to come before letting 2015 come to a close. CROs, the dynamically linked libraries of
|
||||
the 3DS (similiar to DLLs on Windows), blocked several very popular 3DS games from booting in Citra, such as Pokemon
|
||||
X, Y, Omega Ruby, Alpha Sapphire and Super Smash Bros. for 3DS. While the implementation was far from done, it still
|
||||
was able to boot up some of the games that relied heavily on this feature.
|
||||
|
||||
{{< youtube 30NwGUYmIpU >}}
|
||||
|
||||
## Citra in 2016
|
||||
|
||||
With 2016 already upon us, it's shaping up to be a pretty exciting year for Citra! In addition to the many tasks discussed in the 2015 progress reports that are still ongoing, we've got several exciting new features to look forward to:
|
||||
With 2016 already upon us, it's shaping up to be a pretty exciting year for Citra! In addition to the many tasks
|
||||
discussed in the 2015 progress reports that are still ongoing, we've got several exciting new features to look forward
|
||||
to:
|
||||
|
||||
* [MerryMage](https://github.com/merrymage) has been making some exciting progress on an HLE implementation of the DSP, meaning audio support may come sooner than expected!
|
||||
* [tfarley](https://github.com/tfarley) has been working on a HW renderer optimization - "texture forwarding" - that minimizes copies of textures/framebuffers to/from emulated RAM. The result of this effort will be both a performance improvement as well as support for upscaled rendering!
|
||||
* [yuriks](https://github.com/yuriks) has plans to rewrite the vertex shader JIT to fix several inherent flaws, which will improve accuracy and address the crashing issues, as well as improved memory and IPC emulation in the kernel HLE
|
||||
* [Subv](https://github.com/Subv) is still looking into CRO support, as well as mipmapping and scissor testing
|
||||
* [ds84182](http://github.com/ds84182) is currently working on an implementation of Pica's geometry shaders
|
||||
* [bunnei](https://github.com/bunnei) has plans to work on Circle Pad Pro (required for getting Majora's Mask in game), CROs, and a JIT compiler for faster CPU emulation
|
||||
* [Lioncash](https://github.com/lioncash) has plans to continue working on ARM11 CPU emulation, improving both accuracy and performance
|
||||
* [MerryMage](https://github.com/merrymage) has been making some exciting progress on an HLE implementation of the DSP,
|
||||
meaning audio support may come sooner than expected!
|
||||
* [tfarley](https://github.com/tfarley) has been working on a HW renderer optimization - "texture forwarding" - that
|
||||
minimizes copies of textures/framebuffers to/from emulated RAM. The result of this effort will be both a performance
|
||||
improvement as well as support for upscaled rendering!
|
||||
* [yuriks](https://github.com/yuriks) has plans to rewrite the vertex shader JIT to fix several inherent flaws, which
|
||||
will improve accuracy and address the crashing issues, as well as improved memory and IPC emulation in the kernel
|
||||
HLE.
|
||||
* [Subv](https://github.com/Subv) is still looking into CRO support, as well as mipmapping and scissor testing.
|
||||
* [ds84182](http://github.com/ds84182) is currently working on an implementation of Pica's geometry shaders.
|
||||
* [bunnei](https://github.com/bunnei) has plans to work on Circle Pad Pro (required for getting Majora's Mask in game),
|
||||
CROs, and a JIT compiler for faster CPU emulation.
|
||||
* [Lioncash](https://github.com/lioncash) has plans to continue working on ARM11 CPU emulation, improving both accuracy
|
||||
and performance.
|
||||
|
||||
With all of these exciting new features upcoming, it's quite possible that 2016 might be the year that Citra becomes official with a v1.0 release!
|
||||
With all of these exciting new features upcoming, it's quite possible that 2016 might be the year that Citra becomes
|
||||
official with a v1.0 release!
|
||||
|
||||
## Special Thanks from Bunnei
|
||||
|
||||
While working on this article, I found that it was easy to find major changes to write about, but that these really only captured a fraction of the progress made in 2015 – as there was work done literally every single day to make Citra what it is now. While I wish I could draw attention to every contribution made, that’s just not reasonable to do in one article – so instead I’d like to personally thank each person that impacted Citra in the past year: [Lioncash](https://github.com/lioncash), [yuriks](https://github.com/yuriks), [neobrain](http://github.com/neobrain), [Subv](https://github.com/Subv), [archshift](http://github.com/archshift), [linkmauve](http://github.com/linkmauve), [tfarley](https://github.com/tfarley), [purpasmart96](http://github.com/purpasmart96),[aroulin](http://github.com/aroulin), [chinhodado](https://github.com/chinhodado), [polaris-](https://github.com/polaris-), [zawata](http://github.com/zawata), [kevinhartman](http://github.com/kevinhartman), [Cruel](http://github.com/cruel), [Lectem](http://github.com/lectem), [jroweboy](http://github.com/jroweboy), [LittleWhite-tb](http://github.com/littlewhite-tb), [Normmatt](http://github.com/normmatt), [kemenaran](http://github.com/kemenaran), [rohit-n](http://github.com/rohit-n), [Yllodra](http://github.com/yllodra), [xsacha](http://github.com/xsacha), [darkf](http://github.com/darkf), [filfat](http://github.com/filfat), [SeannyM](http://github.com/seannym), [uppfinnarn](http://github.com/uppfinnarn), [Kingcom](http://github.com/kingcom), [Zaneo](http://github.com/zaneo), [wwylele](http://github.com/wwylele), [Zangetsu38](http://github.com/zangetsu38), [Apology11](http://github.com/apology11), [Kloen](http://github.com/kloen), [MoochMcGee](http://github.com/moochmcgee), [gwicks](http://github.com/gwicks), [vaguilar](http://github.com/vaguilar), [chrisvj](http://github.com/chrisvj), [Sethpaien](http://github.com/sethpaien), [Gareth422](http://github.com/gareth422), [JSFernandes](http://github.com/jsfernandes), [esoteric-programmer](http://github.com/esoteric-programmer), [martinlindhe](http://github.com/martinlindhe), [clienthax](http://github.com/clienthax), [ILOVEPIE](http://github.com/ILOVEPIE), [zhuowei](http://github.com/zhuowei), [Bentley](http://github.com/bentley), [mailwl](http://github.com/mailwl), [Disruption](http://github.com/disruption), [LFsWang](http://github.com/lfswang), [Antidote](http://github.com/antidote), [ichfly](http://github.com/ichfly). I can’t wait to see what you guys bring for 2016!
|
||||
While working on this article, I found that it was easy to find major changes to write about, but that these really only
|
||||
captured a fraction of the progress made in 2015 – as there was work done literally every single day to make Citra what
|
||||
it is now. While I wish I could draw attention to every contribution made, that’s just not reasonable to do in one
|
||||
article – so instead I’d like to personally thank each person that impacted Citra in the past year:
|
||||
[Lioncash](https://github.com/lioncash), [yuriks](https://github.com/yuriks), [neobrain](http://github.com/neobrain),
|
||||
[Subv](https://github.com/Subv), [archshift](http://github.com/archshift), [linkmauve](http://github.com/linkmauve),
|
||||
[tfarley](https://github.com/tfarley), [purpasmart96](http://github.com/purpasmart96),
|
||||
[aroulin](http://github.com/aroulin), [chinhodado](https://github.com/chinhodado),
|
||||
[polaris-](https://github.com/polaris-), [zawata](http://github.com/zawata),
|
||||
[kevinhartman](http://github.com/kevinhartman), [Cruel](http://github.com/cruel), [Lectem](http://github.com/lectem),
|
||||
[jroweboy](http://github.com/jroweboy), [LittleWhite-tb](http://github.com/littlewhite-tb),
|
||||
[Normmatt](http://github.com/normmatt), [kemenaran](http://github.com/kemenaran), [rohit-n](http://github.com/rohit-n),
|
||||
[Yllodra](http://github.com/yllodra), [xsacha](http://github.com/xsacha), [darkf](http://github.com/darkf),
|
||||
[filfat](http://github.com/filfat), [SeannyM](http://github.com/seannym), [uppfinnarn](http://github.com/uppfinnarn),
|
||||
[Kingcom](http://github.com/kingcom), [Zaneo](http://github.com/zaneo), [wwylele](http://github.com/wwylele),
|
||||
[Zangetsu38](http://github.com/zangetsu38), [Apology11](http://github.com/apology11), [Kloen](http://github.com/kloen),
|
||||
[MoochMcGee](http://github.com/moochmcgee), [gwicks](http://github.com/gwicks), [vaguilar](http://github.com/vaguilar),
|
||||
[chrisvj](http://github.com/chrisvj), [Sethpaien](http://github.com/sethpaien),
|
||||
[Gareth422](http://github.com/gareth422), [JSFernandes](http://github.com/jsfernandes),
|
||||
[esoteric-programmer](http://github.com/esoteric-programmer), [martinlindhe](http://github.com/martinlindhe),
|
||||
[clienthax](http://github.com/clienthax), [ILOVEPIE](http://github.com/ILOVEPIE), [zhuowei](http://github.com/zhuowei),
|
||||
[Bentley](http://github.com/bentley), [mailwl](http://github.com/mailwl), [Disruption](http://github.com/disruption),
|
||||
[LFsWang](http://github.com/lfswang), [Antidote](http://github.com/antidote), [ichfly](http://github.com/ichfly).
|
||||
|
||||
I can’t wait to see what you guys bring for 2016!
|
||||
|
|
|
@ -6,98 +6,162 @@ author = "jmc47"
|
|||
forum = 37
|
||||
+++
|
||||
|
||||
Welcome to the first Citra Progress Report of 2016! While 2015 will be considered the year that Citra first played games, 2016 is quickly shaping up as a year filled with higher compatibility, greater stability and much more as Citra matures. The avalanche of new features from tons of contributors has made it hard to keep up with everything even for developers!
|
||||
|
||||
Because there have been so many changes and there are so many different games, it can be very hard to keep up with what is working and what is not. To try and make things a little easier, we've compiled some of the biggest changes of the new year together to show you just how far Citra has come already!
|
||||
|
||||
Welcome to the first Citra Progress Report of 2016! While 2015 will be considered the year that Citra first played
|
||||
games, 2016 is quickly shaping up as a year filled with higher compatibility, greater stability and much more as Citra
|
||||
matures. The avalanche of new features from tons of contributors has made it hard to keep up with everything even for
|
||||
developers!
|
||||
|
||||
Because there have been so many changes and there are so many different games, it can be very hard to keep up with what
|
||||
is working and what is not. To try and make things a little easier, we've compiled some of the biggest changes of the
|
||||
new year together to show you just how far Citra has come already!
|
||||
|
||||
## [Immediate Mode Vertex Submission Part 1](https://github.com/citra-emu/citra/pull/1394) and [Part 2](https://github.com/citra-emu/citra/pull/1461) by [ds84182](https://github.com/ds84182) & [yuriks](https://github.com/yuriks)
|
||||
|
||||
Immediate Mode Vertex Submission is a second way for the PICA200 (aka the 3DS GPU) to draw vertices. Unlike the normal method, Immediate Mode trades off some efficiency when drawing complex models for less overhead on each object. This makes it a suitable option for things such as UI elements. Despite all of that, it's capable of being used for just about anything, and some games use it for drawing all of their graphics.
|
||||
Immediate Mode Vertex Submission is a second way for the PICA200 (aka the 3DS GPU) to draw vertices. Unlike the normal
|
||||
method, Immediate Mode trades off some efficiency when drawing complex models for less overhead on each object. This
|
||||
makes it a suitable option for things such as UI elements. Despite all of that, it's capable of being used for just
|
||||
about anything, and some games use it for drawing all of their graphics.
|
||||
|
||||
[ds84182](https://github.com/ds84182) first implemented the feature and showed just how many games it could fix. After it was merged, some issues were found and [yuriks](https://github.com/yuriks) fixed some edge cases and added support for *vertex restart*. Vertex Restart is a feature necessary when drawing using triangle strips, in order to break apart consecutive strips.
|
||||
|
||||
<p style="text-align: center;"> <img alt="" src="/images/entry/citra-progress-report-2016-p1/etrianodysseytop.png" style="width: 400px; height: 240px;" /><img alt="" src="/images/entry/citra-progress-report-2016-p1/etrianodysseybottom.png" style="width: 320px; height: 240px;" />
|
||||
|
||||
<p style="text-align: center;">Etrian Odyssey IV running in Citra with Immediate Mode Vertex Submission
|
||||
|
||||
With this, along with previous fixes of [#1462](https://github.com/citra-emu/citra/pull/1462) and [#1624](https://github.com/citra-emu/citra/pull/1624) for correct depth writing behaviors, Etrian Odyssey IV and other games appear to be playable in Citra.
|
||||
[ds84182](https://github.com/ds84182) first implemented the feature and showed just how many games it could fix. After
|
||||
it was merged, some issues were found and [yuriks](https://github.com/yuriks) fixed some edge cases and added support
|
||||
for *vertex restart*. Vertex Restart is a feature necessary when drawing using triangle strips, in order to break apart
|
||||
consecutive strips.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/etrianodysseytop.png"
|
||||
alt="Etrian Odyssey IV"
|
||||
title="Etrian Odyssey IV running in Citra with Immediate Mode Vertex Submission" >}}
|
||||
|
||||
With this, along with previous fixes of [#1462](https://github.com/citra-emu/citra/pull/1462) and
|
||||
[#1624](https://github.com/citra-emu/citra/pull/1624) for correct depth writing behaviors, Etrian Odyssey IV and other
|
||||
games appear to be playable in Citra.
|
||||
|
||||
## [Unicode Support on Windows](https://github.com/citra-emu/citra/pull/1541) by [LFsWang](https://github.com/LFsWang)
|
||||
|
||||
Due to the different way Windows reports filenames to programs compared to Linux or OS X, Citra was previously unable to load any files with a path containing non-English characters. That is, if your file was named using accented letters, Chinese, Japanese characters, emoji, or in general any characters not present in the [ASCII](https://en.wikipedia.org/wiki/ASCII) character set, Citra would be unable to find the file! Considering Citra is developed and used by people around the world, this was a very important issue. We did not want people to need to rename files or directories to be able to open them with Citra.
|
||||
|
||||
[LFsWang](https://github.com/LFsWang) took the time to fix the frontend code so that Citra was able to correctly load these files. [More recently](https://github.com/citra-emu/citra/pull/1620) further improvements were made so that this works correctly even if you're loading files with characters from a language different than the one running on your operating system.
|
||||
|
||||
Due to the different way Windows reports filenames to programs compared to Linux or OS X, Citra was previously unable
|
||||
to load any files with a path containing non-English characters. That is, if your file was named using accented
|
||||
letters, Chinese, Japanese characters, emoji, or in general any characters not present in the
|
||||
[ASCII](https://en.wikipedia.org/wiki/ASCII) character set, Citra would be unable to find the file! Considering Citra
|
||||
is developed and used by people around the world, this was a very important issue. We did not want people to need to
|
||||
rename files or directories to be able to open them with Citra.
|
||||
|
||||
[LFsWang](https://github.com/LFsWang) took the time to fix the frontend code so that Citra was able to correctly load
|
||||
these files. [More recently](https://github.com/citra-emu/citra/pull/1620) further improvements were made so that this
|
||||
works correctly even if you're loading files with characters from a language different than the one running on your
|
||||
operating system.
|
||||
|
||||
## [Fix MAD/MADI Shader Instruction Encoding](https://github.com/citra-emu/citra/pull/1479) by [JayFoxRox](https://github.com/JayFoxRox)
|
||||
|
||||
MAD and MADI (Multiply-Add and Multiply-Add Inverted, respectively.) are shader instructions in the PICA200 GPU, handled by Citra's shader JIT and interpreter. These instructions execute a multiplication followed by an addition (*d* = *a* × *b* + *c*) in the same instruction. They're unique in that they're the only instructions that works with 3 source operands, and thus have a special way of being encoded into the program. Citra interpreted this format incorrectly, causing it to sometimes operate on the wrong values!
|
||||
MAD and MADI (Multiply-Add and Multiply-Add Inverted, respectively.) are shader instructions in the PICA200 GPU, handled
|
||||
by Citra's shader JIT and interpreter. These instructions execute a multiplication followed by an addition
|
||||
(*d* = *a* × *b* + *c*) in the same instruction. They're unique in that they're the only instructions that works with
|
||||
3 source operands, and thus have a special way of being encoded into the program. Citra interpreted this format
|
||||
incorrectly, causing it to sometimes operate on the wrong values!
|
||||
|
||||
Handling these instructions correctly, much like a CPU emulator, is paramount for accurate emulation. In this case, it happened that these instructions were commonly used in font rendering shaders, and this bug often manifested as gibberish textures and incorrect positioning, as can be seen in this The Legend of Zelda: A Link Between Worlds screenshot:
|
||||
|
||||
<p style="text-align: center;"><img alt="" src="/images/entry/citra-progress-report-2016-p1/albwbefore.png" style="width: 400px; height: 480px;" /><img alt="" src="/images/entry/citra-progress-report-2016-p1/albwafter.jpg" style="width: 400px; height: 480px;" />
|
||||
|
||||
<p style="text-align: center;">The Hylian language just seems to get harder and harder to read every game! Oh... wait.
|
||||
|
||||
Considering that emulators over a decade older than Citra are still finding problems with how CPU instructions are handled, it's no surprise that our shaders aren't bullet-proof yet either. There should be many, many games affected by the encoding fixes, so if you've been seeing gibberish text or other problems, there's a fair chance that this change could have fixed the bug.
|
||||
Handling these instructions correctly, much like a CPU emulator, is paramount for accurate emulation. In this case, it
|
||||
happened that these instructions were commonly used in font rendering shaders, and this bug often manifested as
|
||||
gibberish textures and incorrect positioning, as can be seen in this The Legend of Zelda: A Link Between Worlds
|
||||
screenshot:
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/albwbefore.png" >}}
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/albwafter.jpg"
|
||||
title="The Hylian language just seems to get harder and harder to read every game! Oh... wait." >}}
|
||||
|
||||
Considering that emulators over a decade older than Citra are still finding problems with how CPU instructions are
|
||||
handled, it's no surprise that our shaders aren't bullet-proof yet either. There should be many, many games affected
|
||||
by the encoding fixes, so if you've been seeing gibberish text or other problems, there's a fair chance that this
|
||||
change could have fixed the bug.
|
||||
|
||||
## [Align Attribute Components](https://github.com/citra-emu/citra/pull/1496) by [JayFoxRox](https://github.com/JayFoxRox)
|
||||
|
||||
Vertex Attributes are an integral step in rendering. They can tell the GPU the bone weight, color, position, etc. So when [JayFoxRox](http://github.com/JayFoxRox) discovered that the Vertex Attributes were misaligned and pulling the incorrect values, he knew he stumbled upon a major problem. One game in particular affected by this was Super Smash Bros. 4, which since the MAD/MADI fixes had been displaying some graphics, although things looked pretty messed up.
|
||||
|
||||
<p style="text-align: center;"><img alt="Pikachu has seen better days." src="/images/entry/citra-progress-report-2016-p1/smashbrosbefore.jpg" style="width: 400px; height: 240px;" /><img alt="While lighting is a bit off, the game looks fairly playable!" src="/images/entry/citra-progress-report-2016-p1/smashbrosafter.png" style="width: 400px; height: 240px;" />
|
||||
|
||||
<p style="text-align: center;">With this fix, the Super Smash Bros. 4 actually looks fairly playable!
|
||||
|
||||
The align attributes fixes should also fix other games where the graphics tend to explode like Super Smash Bros. 4.
|
||||
Vertex Attributes are an integral step in rendering. They can tell the GPU the bone weight, color, position, etc. So
|
||||
when [JayFoxRox](http://github.com/JayFoxRox) discovered that the Vertex Attributes were misaligned and pulling the
|
||||
incorrect values, he knew he stumbled upon a major problem. One game in particular affected by this was Super Smash
|
||||
Bros. 4, which since the MAD/MADI fixes had been displaying some graphics, although things looked pretty messed up.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/smashbrosbefore.jpg"
|
||||
title="Pikachu has seen better days." >}}
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/smashbrosafter.png"
|
||||
title="While lighting is a bit off, the game looks fairly playable!" >}}
|
||||
|
||||
With this fix, the Super Smash Bros. 4 actually looks fairly playable! The align attributes fixes should also fix other
|
||||
games where the graphics tend to explode like Super Smash Bros. 4.
|
||||
|
||||
## [Save Fixes](https://github.com/citra-emu/citra/pull/1302) by [Subv](https://github.com/Subv)
|
||||
|
||||
One of the more notable problems that Citra has currently is that many games require a savefile extracted from the 3DS in order to get in game. This is due to many reasons, including partial or incorrect file system and OS emulation. Because getting saves from newer games can be problematic due to encryption (and it's generally a pain anyway), getting Citra to create and load savegames properly is a very important task that will continue to be a priority for the forseeable future.
|
||||
One of the more notable problems that Citra has currently is that many games require a savefile extracted from the 3DS
|
||||
in order to get in game. This is due to many reasons, including partial or incorrect file system and OS emulation.
|
||||
Because getting saves from newer games can be problematic due to encryption (and it's generally a pain anyway), getting
|
||||
Citra to create and load savegames properly is a very important task that will continue to be a priority for the
|
||||
forseeable future.
|
||||
|
||||
The save fixes recently merged mostly have to do with formatting the cartridge saves correctly. 3DS titles are very picky about how their saves are formatted and will often fail if all of the files aren't handled *exactly* like they want. This was the reason why Mario Kart 7 would hang in Citra! And once you're in game, it is quite the visual treat for a 3DS title!
|
||||
The save fixes recently merged mostly have to do with formatting the cartridge saves correctly. 3DS titles are very
|
||||
picky about how their saves are formatted and will often fail if all of the files aren't handled *exactly* like they
|
||||
want. This was the reason why Mario Kart 7 would hang in Citra! And once you're in game, it is quite the visual treat
|
||||
for a 3DS title!
|
||||
|
||||
<p style="text-align: center;"><img alt="" src="/images/entry/citra-progress-report-2016-p1/mk7.jpg" style="width: 800px; height: 441px;" />
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/mk7.jpg"
|
||||
title="Mario Kart 7 is now fully playable in Citra and looking better than ever!" >}}
|
||||
|
||||
<p style="text-align: center;">Mario Kart 7 is now fully playable in Citra and looking better than ever!
|
||||
|
||||
The above change fixes Mario Kart 7, Final Fantasy Explorers, Lego Batman 3: Beyond Gotham, The Amazing Spiderman, and likely many others games that previously hung while creating or deleting savefiles.
|
||||
The above change fixes Mario Kart 7, Final Fantasy Explorers, Lego Batman 3: Beyond Gotham, The Amazing Spiderman, and
|
||||
likely many others games that previously hung while creating or deleting savefiles.
|
||||
|
||||
## [Clear Shader JIT Cache](https://github.com/citra-emu/citra/pull/1503) by [bunnei](https://github.com/bunnei)
|
||||
|
||||
Citra's GPU shader JIT had a bit of a flaw: It would keep previously compiled shaders in memory forever. Furthermore, it only allocated a fixed amount of space for all compiled shader code. When testing the early games that booted on Citra, none of this seemed to matter and things continued fine. But, as Citra has been running more complex games and was being used by more users for longer periods of time, it became apparent that this simply wasn't good enough. Games were managing to fill up the fixed amount of space that Citra had allocated for the Shader JIT Cache and crashing the emulator!
|
||||
Citra's GPU shader JIT had a bit of a flaw: It would keep previously compiled shaders in memory forever. Furthermore,
|
||||
it only allocated a fixed amount of space for all compiled shader code. When testing the early games that booted on
|
||||
Citra, none of this seemed to matter and things continued fine. But, as Citra has been running more complex games and
|
||||
was being used by more users for longer periods of time, it became apparent that this simply wasn't good enough. Games
|
||||
were managing to fill up the fixed amount of space that Citra had allocated for the Shader JIT Cache and crashing the
|
||||
emulator!
|
||||
|
||||
[bunnei](https://github.com/bunnei) added a simple fix to the memory management which allows Citra to drop old, unused shaders in order to free up space for new ones being requested by the game, fixing these crashes and allowing for longer game sessions. For example, Kirby: Triple Deluxe is now stable in Citra, even when using the Shader JIT:
|
||||
[bunnei](https://github.com/bunnei) added a simple fix to the memory management which allows Citra to drop old, unused
|
||||
shaders in order to free up space for new ones being requested by the game, fixing these crashes and allowing for
|
||||
longer game sessions. For example, Kirby: Triple Deluxe is now stable in Citra, even when using the Shader JIT:
|
||||
|
||||
<p style="text-align: center;"><img alt="" src="/images/entry/citra-progress-report-2016-p1/b.png" style="width: 400px; height: 240px;" /><img alt="" src="/images/entry/citra-progress-report-2016-p1/c.png" style="width: 400px; height: 240px;" />
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/b.png" >}}
|
||||
|
||||
<p style="text-align: center;">Kirby: Triple Deluxe used to crash almost immediately while in game
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/c.png"
|
||||
title="Kirby: Triple Deluxe used to crash almost immediately while in game" >}}
|
||||
|
||||
## [Shader JIT Refactor](https://github.com/citra-emu/citra/pull/1546) by [bunnei](https://github.com/bunnei)
|
||||
|
||||
While most of the issues with the shader JIT were fixed with the aforemoentioned changes, there remained a fundamental flaw with how flow control was handled. Previously, the shader JIT inlined CALL and JMP instructions. This had several issues: 1) Inlining all subroutines resulted in bloated shaders being generated, and 2) jumping to arbitrary addresses (and nested jumps) couldn't be supported. This is because when inlining code, the same source shader code might be recompiled multiple times. To support arbitrary jumps, there needed to be a one-to-one mapping of source code to compiled code.
|
||||
While most of the issues with the shader JIT were fixed with the aforemoentioned changes, there remained a fundamental
|
||||
flaw with how flow control was handled. Previously, the shader JIT inlined CALL and JMP instructions. This had several
|
||||
issues: 1) Inlining all subroutines resulted in bloated shaders being generated, and 2) jumping to arbitrary addresses
|
||||
(and nested jumps) couldn't be supported. This is because when inlining code, the same source shader code might be
|
||||
recompiled multiple times. To support arbitrary jumps, there needed to be a one-to-one mapping of source code to
|
||||
compiled code.
|
||||
|
||||
To fix this, [bunnei](https://github.com/bunnei) refactored the shader JIT to do a multiple step compile: First, analyze the shader and identify subroutines, jumps, and return locations. Next, compile the code (just once), and insert additional code to handle the returns and jumps. In addition to enabling arbitrary CALL/JMP instructions, this results in pretty constant compiled shader sizes of around 40kb, which significantly reduced the memory footprint of the shader JIT.
|
||||
To fix this, [bunnei](https://github.com/bunnei) refactored the shader JIT to do a multiple step compile: First,
|
||||
analyze the shader and identify subroutines, jumps, and return locations. Next, compile the code (just once), and
|
||||
insert additional code to handle the returns and jumps. In addition to enabling arbitrary CALL/JMP instructions, this
|
||||
results in pretty constant compiled shader sizes of around 40kb, which significantly reduced the memory footprint of
|
||||
the shader JIT.
|
||||
|
||||
This change fixes IronFall: Invasion, Pokemon: Rumble Blast, and several other games:
|
||||
|
||||
<p style="text-align: center;"><img alt="" src="/images/entry/citra-progress-report-2016-p1/1.png" style="width: 400px; height: 240px;" /><img alt="" src="/images/entry/citra-progress-report-2016-p1/2.png" style="width: 320px; height: 240px;" />
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/1.png" >}}
|
||||
|
||||
<p style="text-align: center;">With these changes, all known graphical glitches with IronFall: Invasion are fixed in Citra
|
||||
{{< figure src="/images/entry/citra-progress-report-2016-p1/2.png"
|
||||
title="With these changes, all known graphical glitches with IronFall: Invasion are fixed in Citra" >}}
|
||||
|
||||
## [Audio Framework](https://github.com/citra-emu/citra/pull/1386) by [MerryMage](https://github.com/merrymage)
|
||||
|
||||
We'd like to mention the amazing work done by [MerryMage](https://github.com/merrymage) to bring proper DSP HLE and audio support to Citra. Over the past few months, she has been carefully chipping away at figuring out how audio 3DS works, removing several hacks in Citra along the way. While many of her efforts have been transparent to users up until this point, they have laid the groundwork for soon-to-come audio support. With changes [#1386](https://github.com/citra-emu/citra/pull/1386), [#1403](https://github.com/citra-emu/citra/pull/1403), [#1441](https://github.com/citra-emu/citra/pull/1441), [#1566](https://github.com/citra-emu/citra/pull/1566), and [#1572](https://github.com/citra-emu/citra/pull/1572), we're now closer than ever to hearing games for the first time in Citra! While [MerryMage](http://github.com/merrymage) has audio nearly complete in unofficial branches, there are still a few remaining issues before it gets merged.
|
||||
We'd like to mention the amazing work done by [MerryMage](https://github.com/merrymage) to bring proper DSP HLE and
|
||||
audio support to Citra. Over the past few months, she has been carefully chipping away at figuring out how audio 3DS
|
||||
works, removing several hacks in Citra along the way. While many of her efforts have been transparent to users up
|
||||
until this point, they have laid the groundwork for soon-to-come audio support. With changes
|
||||
[#1386](https://github.com/citra-emu/citra/pull/1386), [#1403](https://github.com/citra-emu/citra/pull/1403),
|
||||
[#1441](https://github.com/citra-emu/citra/pull/1441), [#1566](https://github.com/citra-emu/citra/pull/1566), and
|
||||
[#1572](https://github.com/citra-emu/citra/pull/1572), we're now closer than ever to hearing games for the first time
|
||||
in Citra! While [MerryMage](http://github.com/merrymage) has audio nearly complete in unofficial branches, there are
|
||||
still a few remaining issues before it gets merged.
|
||||
|
||||
## Contributors of 2016
|
||||
|
||||
We've got a fortunate problem to have: It's often too difficult to mention every contribution made to Citra when writing progress reports! We'd like to extend a special thanks [to all that helped advance Citra further](https://github.com/citra-emu/citra/graphs/contributors?from=2016-01-01&to=2016-04-19&type=c) since our last progress report, you guys rock!
|
||||
We've got a fortunate problem to have: It's often too difficult to mention every contribution made to Citra when
|
||||
writing progress reports! We'd like to extend a special thanks
|
||||
[to all that helped advance Citra further](https://github.com/citra-emu/citra/graphs/contributors?from=2016-01-01&to=2016-04-19&type=c)
|
||||
since our last progress report, you guys rock!
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
+++
|
||||
date = "2017-09-16T00:28:00-04:00"
|
||||
title = "Citra Progress Report - 2017 August"
|
||||
tags = [ "progress-report" ]
|
||||
author = "anodium"
|
||||
coauthor = "saphiresurf"
|
||||
forum = 3566
|
||||
+++
|
||||
|
||||
2017 has been an amazing year, with more work having been put into the project
|
||||
than ever before, but it's not over yet! Last we met was
|
||||
[June](/entry/citra-progress-report-2017-june/), and just two months later the
|
||||
[Citra issue tracker](https://github.com/citra-emu/citra/pulls) is brimming with
|
||||
lots of changes once more. I am extremely excited for this month (and what's coming
|
||||
up the next few months) but we're getting ahead of ourselves! On this progress
|
||||
report, let's check out the big fish in the July and August pond of patches!
|
||||
|
||||
## Updating The Software Renderer ([This](https://github.com/citra-emu/citra/pull/2766), [that](https://github.com/citra-emu/citra/pull/2822), [here](https://github.com/citra-emu/citra/pull/2871), [there](https://github.com/citra-emu/citra/pull/2872), and [those](https://github.com/citra-emu/citra/pull/2891)) by [wwylele](https://github.com/wwylele) and [Subv](https://github.com/Subv)
|
||||
|
||||
Citra has two main rendering backends, software and OpenGL, but until very
|
||||
recently, no one gave much attention to the software backend. The OpenGL backend
|
||||
is faster, makes better use of the GPU, and allows things such as texture forwarding
|
||||
for higher resolution rendering. But there is one thing on which the OpenGL backend
|
||||
falls flat on its face---accuracy.
|
||||
|
||||
However, [wwylele](https://github.com/wwylele) has just revived the software
|
||||
renderer (inspired by an attempt [Subv](https://github.com/Subv) made prior),
|
||||
adding almost all of the features the hardware renderer had received over the years.
|
||||
In fact, every addition to the hardware renderer has been given an equivalent
|
||||
in software:
|
||||
|
||||
{{% table %}}
|
||||
| Feature | Hardware | Software |
|
||||
| ----------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| Fragment Lighting | [#1264](https://github.com/citra-emu/citra/pull/1264) | [#2766](https://github.com/citra-emu/citra/pull/2766), [#2822](https://github.com/citra-emu/citra/pull/2822) |
|
||||
| Spot Lighting | [#2727](https://github.com/citra-emu/citra/pull/2727) | [#2871](https://github.com/citra-emu/citra/pull/2871) |
|
||||
| Geometric Factor | [#2776](https://github.com/citra-emu/citra/pull/2776) | [#2872](https://github.com/citra-emu/citra/pull/2872) |
|
||||
| Bump Mapping | [#2762](https://github.com/citra-emu/citra/pull/2762) | [#2891](https://github.com/citra-emu/citra/pull/2891) |
|
||||
{{% /table %}}
|
||||
|
||||
Despite the software backend being incredibly slow, it is important to have a
|
||||
complete software implementation of the 3DS' GPU so that Citra can be used as a
|
||||
stable, working, and complete reference implementation in the future, when
|
||||
obtaining a working real console may be much more difficult.
|
||||
|
||||
## [Handle Invalid Filenames When Renaming](https://github.com/citra-emu/citra/pull/2850) by [j-selby](https://github.com/j-selby)
|
||||
|
||||
Citra emulates the 3DS system services at a high level of emulation, or HLE for
|
||||
short. What this means is that every time a 3DS application or game running in
|
||||
Citra makes a request to the 3DS System Software, Citra captures the request and
|
||||
tries to translate it into its PC equivalent, rather then running the 3DS System
|
||||
Software directly.
|
||||
|
||||
For example, if a game makes a call to [`FS:OpenFile`](https://www.3dbrew.org/wiki/FS:OpenFile),
|
||||
Citra in turn calls the operating system's file opening function
|
||||
([`_wfopen_s()`](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-s-wfopen-s) on Windows,
|
||||
or [`open()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) on macOS and Linux),
|
||||
with [the path to the virtual SD card](/wiki/user-directory/) added to the beginning.
|
||||
|
||||
Now, on top of the usual names for files and folders, there's two special folders
|
||||
inside every single folder on your computer, `.` and `..`. These aren't actual
|
||||
folders in the sense that you can place files and other folders inside of them.
|
||||
Instead, they each symbolize the current folder, and the folder one level above
|
||||
it, respectively. For example, `C:/Windows/System32/..` actually means `C:/Windows/`.
|
||||
|
||||
With this in mind, a few Citra developers believed a game could, in theory, chain
|
||||
multiple `..`s together to get to a file they weren't supposed to know even existed,
|
||||
like `/../../../../Documents/IMPORTANT.docx`. Citra would then ask the operating
|
||||
system to open the file `%AppData%/Citra/sdmc/../../../../Documents/IMPORTANT.docx`,
|
||||
which *actually* means that it would open `C:/Users/Anodium/Documents/IMPORTANT.docx`!
|
||||
|
||||
Before you suggest that Citra simply ignore `..`, a game can use it for legitimate
|
||||
purposes. And if it were to use it, it would most likely crash, as the resulting
|
||||
file path wouldn't exist.
|
||||
|
||||
This was already handled for most file functions in Citra, opening, reading,
|
||||
writing, etc. except for a few things, like renaming a file. In this case, the
|
||||
malicious game could just ask Citra to change `/../../../../Documents/IMPORTANT.docx`'s
|
||||
name to `/delicious_secrets.docx`, effectively moving `IMPORTANT.docx` into Citra's
|
||||
virtual SD card! From there, the game could just ask Citra to open
|
||||
`/delicious_secrets.docx` to read the file it was originally forbidden from accessing.
|
||||
|
||||
This patch now fixes this, such that if any 3DS game or application tries to do
|
||||
exploit the rename file function from inside Citra, rather than doing what it asks,
|
||||
Citra gives them `ERROR_INVALID_PATH`, which most games interpret by crashing. So
|
||||
far, we haven't found any real 3DS software that tries to do this, but at least
|
||||
now future attempts to do so are blocked.
|
||||
|
||||
Do note though, that most of us are not security experts, and even for those who are,
|
||||
harderning the software is much more difficult and much less worthwhile than actually
|
||||
having an accurate 3DS emulation. The surface area of an emulation project is huge,
|
||||
and so writing malicious code intending to exploit one is not too difficult in any case.
|
||||
|
||||
But at the same time, malware authors generally target either the largest populations,
|
||||
or the most lucrative populations, and emulation is neither. And for the effort
|
||||
required to do so, most will only toy with the idea in their head, or maybe write
|
||||
a proof-of-concept for fun, rather than genuine malicious intent.
|
||||
|
||||
## [Fix Edge Cases for TextureCopy](https://github.com/citra-emu/citra/pull/2809) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
The 3DS GPU has a data transfer mode called `TextureCopy`, which as the name says,
|
||||
is for copying textures but with a configurable gap in case the texture is going
|
||||
to be copied into a smaller resolution area. This mode is enabled by setting the
|
||||
3rd flag in the GPU and causes it to ignore every other flag except the 2nd, which
|
||||
is used to tell it whether or not to crop the texture.
|
||||
|
||||
This is nice because it can be used as a quick and easy way for 3DS developers to
|
||||
duplicate textures, and can be used in situations such as the one pictured running
|
||||
on hardware in Pokémon Super Mystery Dungeon below. But when it came to running
|
||||
something that took advantage of this feature in Citra, it didn't always work the
|
||||
same as it would on console.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-august/texturecopy-before.png"
|
||||
title="How jagged" alt="Pokémon Super Mystery Dungeon During Deoxy's and Rayquaza's Face Off I N S P A C E" >}}
|
||||
|
||||
Fortunately (and to much rejoicing!) wwylele stepped into the ring to wrestle with
|
||||
this issue. They prepared a [test program](https://github.com/wwylele/ctrhwtest/tree/master/texture-copy-test)
|
||||
to help gain an understanding of how the hardware handles the TextureCopy operation
|
||||
in comparison to Citra. After the hard work of doing the research was out of the
|
||||
way, wwylele implemented it in Citra.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-august/texturecopy-after.png"
|
||||
title="Deoxys is having a bit of a hard time, no?" alt="Pokémon Super Mystery Dungeon During Deoxy's and Rayquaza's Face Off I N S P A C E" >}}
|
||||
|
||||
## [Use Docker For Linux Builds](https://github.com/citra-emu/citra/pull/2869) by [j-selby](https://github.com/j-selby)
|
||||
|
||||
Ubuntu Linux 14.04 is the de-facto standard desktop Linux distribution. It's also
|
||||
old. [*Very* old](https://wiki.ubuntu.com/TrustyTahr/ReleaseSchedule#line-37).
|
||||
So old, in fact, that the compiler it ships with can't compile Citra. And our
|
||||
buildbot, [Travis CI](https://travis-ci.org/), that automatically compiles and
|
||||
builds Citra from source, just so happens to use Ubuntu 14.04 VMs. *`:(`*
|
||||
|
||||
Formerly, we would update the compiler from a third-party repository before compiling
|
||||
Citra itself. This also had the side-effect of updating the standard library that
|
||||
comes with the compiler, as each compiler version is inextricably tied to the same
|
||||
version of library by design. Unfortunately, a recent update to the library was
|
||||
incompatible with a large majority of systems because it's too new for Ubuntu 14.04,
|
||||
breaking the Linux build once again.
|
||||
|
||||
Now, rather than building Citra directly inside Travis, a
|
||||
[Docker container](https://www.docker.com/) is started that's running Ubuntu 16.04
|
||||
instead, which is much more well supported (and yes, it can compile Citra out of the box!).
|
||||
|
||||
## [UI Themes](https://github.com/citra-emu/citra/pull/2804) by [Kloen](https://github.com/kloen)
|
||||
|
||||
[Kloen](https://github.com/kloen) has put the time and work into Citra's Qt
|
||||
frontend to make it themeable. Now users can enjoy a dark mode and other custom
|
||||
colour schemes, just by editing a CSS stylesheet!
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-august/theme-comparison.png"
|
||||
title="CHOOSE YOUR CHARACTER" alt="Comparison of Dark Theme and Light Theme" >}}
|
||||
|
||||
## [Load Shared Font From System Archive](https://github.com/citra-emu/citra/pull/2784) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
**This does not eliminate the need for dumping a shared font from a legitimate system.**
|
||||
|
||||
This in itself isn't an extremely visible or perceivable change from a user
|
||||
perspective, but it is something that helps us take another stride towards
|
||||
accurately recreating the way the 3DS actually operates. All system data is
|
||||
uniformly stored in the system archive now that the system font can be included
|
||||
with it. Citra does still fall back to the deprecated `shared_font.bin` file if
|
||||
it was dumped before, for compatibility's sake. `3dsutil` has been updated to be
|
||||
able to dump everything as a system archive, so that Citra may be able to work
|
||||
with it in a way that's more accurate to the actual hardware!
|
||||
|
||||
## And Everyone Else
|
||||
|
||||
Just because your work wasn't written on here doesn't mean it's not as important!
|
||||
Every little bit counts, every pull request inches the project one step closer
|
||||
down the long road of accurately emulating the Nintendo 3DS. So I would like to
|
||||
give my thanks to [everyone who's contributed](https://github.com/citra-emu/citra/graphs/contributors?from=2017-07-10&to=2017-08-30&type=c)
|
||||
these past two months, for giving us those extra metres down this road.
|
|
@ -0,0 +1,112 @@
|
|||
+++
|
||||
date = "2017-07-10T12:38:00-04:00"
|
||||
title = "Citra Progress Report - 2017 June"
|
||||
tags = [ "progress-report" ]
|
||||
author = "anodium"
|
||||
forum = 2408
|
||||
+++
|
||||
|
||||
The summer of 2017 has just rolled in, and although we don't have a [summer of code](https://developers.google.com/open-source/gsoc/), the patches continue rolling in regardless. We've got a ton of fixes this month in the renderer, so this report is going to be very screenshot heavy. With that out of the way, let's get right to it.
|
||||
<br />
|
||||
|
||||
## [Implemented Procedural Texture (Texture Unit 3)](https://github.com/citra-emu/citra/pull/2697) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
There is a rarely used feature in the 3DS' GPU called procedural textures, "proctex" for short. It allows games to generate new textures on the fly by just plugging in a few parameters. Mario & Luigi: Paper Jam, and Kirby: Planet Robobot both use it to generate realistic sea surfaces. The formula behind proctex had to be reverse-engineered in order to be implemented, which fortunately [fincs](https://github.com/fincs) did [and documented](https://gist.github.com/fincs/543f7e1375815f495f10020a053f14e9). Using this documentation, [wwylele](https://github.com/wwylele) simply translated it into code, and dropped it into Citra, fixing both those games.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-june/paper-jam-foam.png" title="Look at that beautiful sea foam. ❤"
|
||||
alt="Mario & Luigi: Paper Jam's intro cutscene, showing Peach's castle, and the sea behind it" >}}
|
||||
|
||||
<!--
|
||||
title_id = 0004000000132700
|
||||
commit_hash = c017065570f9bad90a8cd3dadac9b63d810793a6
|
||||
-->
|
||||
|
||||
## [OpenGL: Improve accuracy of quaternion interpolation](https://github.com/citra-emu/citra/pull/2729) by [yuriks](https://github.com/yuriks)
|
||||
|
||||
To calculate lighting on any given object, the 3DS' GPU interpolates the light quaternion with the surface quaternion of that object. There are three main methods to doing so, the **l**inear int**erp**olation (**lerp**), the **q**uadratic **l**inear int**erp**olation (**qlerp**), and the **s**pherical **l**inear int**erp**olation (**slerp**). All this time Citra used a lerp, which, although the fastest, can lead to a lot of distortion when interpolating across a large rotation angle.
|
||||
|
||||
[yuriks](https://github.com/yuriks) researched and implemented slerp on Citra, and after a long while of work, it turns out that the 3DS uses lerp as well! The bug in Citra was caused by not normalizing the quaternions before interpolating them, which greatly affected the results. This particular issue sent them down a very deep rabbit hole, only to lead to a red herring. But, at least it was (eventually) fixed!
|
||||
|
||||
## [Remove built-in disassembler and related code](https://github.com/citra-emu/citra/pull/2689) by [yuriks](https://github.com/yuriks)
|
||||
|
||||
The Citra disassembler and debugger was planned to be a fully-featured debugger for 3DS programs, as how Dolphin, No$GBA, or other emulators have done. Unfortunately, they were never given the care that was needed to get them up to speed, and so it was extremely buggy, disassembling code to complete nonsense at times. Not to mention that it was missing a lot of essential features, such as setting breakpoints. All of these things, combined with the fact that we already have added 3DS support to `gdb`, it just made sense to get rid of this one and focus on the other.
|
||||
|
||||
## Implement the [Circle Pad Pro](https://github.com/citra-emu/citra/pull/2606) and the [New 3DS C-Stick](https://github.com/citra-emu/citra/pull/2676) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
The Circle Pad Pro was an accessory that added a secondary circle pad and ZL/ZR buttons to the old 3DS, years before the New 3DS was even annouced. It communicated with the 3DS via infrared, which allowed dropping the console into it directly without having to plug in any wires or modify the console. The New 3DS' C-stick exposes itself to the system via a new, simpler (and incompatible) API, but for backwards compatibility, still exposes it via the infrared API, this allows games that were made years before the New 3DS to work perfectly well with the C-stick. These two additions give C-stick support to Citra, one through the C-stick API, and one through the infrared API.
|
||||
|
||||
## [gl_rasterizer: fix lighting LUT interpolation](https://github.com/citra-emu/citra/pull/2792) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
For fragment lighting, the 3DS has a hardcoded **L**ook-**u**p **T**able of values to calculate things more quickly, but is relatively small, only 256 entries big. Because of this, for every time a lookup falls between two values, the game has a table, usually in the ROM, but it can be computed on the fly, that has the differences between the closest two values, called the delta table.
|
||||
|
||||
In Citra, to be more efficient, we give the LUT (look-up table) to OpenGL and tell it to filter it, much like how games on PC filter their textures to smooth out jagged edges, and thus doesn't need to compute any differences at all anymore. Unfortunately, because we're treating a table as essentially a 1-dimensional texture (since that's the only concept OpenGL understands), we also need to deal with very big problem that the 3DS' GPU and OpenGL both have different coordinate systems. Coordinate 0 on the 3DS refers the zeroth (i.e. the first, since it starts on 0) entry on the table, but in OpenGL, it means the left corner of the first pixel, which would instead be slightly less than the actual value of the first entry on the table because of the filtering.
|
||||
|
||||
As a workaround, some offsets were set on the table in OpenGL so that it would pick the correct entries. But, the LUT on the 3DS also has a mode called "two's complement" in which each half of the table is "wrapped" virtually across past the beginning and end of the table, but not across the middle of the table. This completely messes up the table in OpenGL, leading to completely different results near the middle of the table, causing things like dark spots in highlighted areas.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-june/lut-fix-before.png" title="Kyogre seems to have a bit of a skin blemish."
|
||||
alt="Kyogre in Pokémon Alpha Sapphire before the fix." >}}
|
||||
|
||||
<!--
|
||||
title_id = 000400000011c500
|
||||
commit_hash = 2f746e9946f78a2e283dfdcbeda9cf332e44d099 cherry-pick 6ca816e011c03f90f9ef6800c747c030df54c0cf 24e0b1ed8d4a24c814496e1b36236687fc0d442f
|
||||
-->
|
||||
|
||||
Although the OpenGL hack provided a slight increase in efficiency, in the end [wwylele](https://github.com/wwylele) replaced it all with simply mimicking what the 3DS does, fixing the entire issue, and making lighting calculations significantly more accurate. Sometimes the simplest solution is the best solution.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-june/lut-fix-after.png" title="Much better, guess the lighting got an acne treatment."
|
||||
alt="Kyogre in Pokémon Alpha Sapphire after the fix." >}}
|
||||
|
||||
<!--
|
||||
title_id = 000400000011c500
|
||||
commit_hash = c017065570f9bad90a8cd3dadac9b63d810793a6
|
||||
-->
|
||||
|
||||
## [Display QMessageBox Dialogs For Errors](https://github.com/citra-emu/citra/pull/2611) by [TheKoopaKingdom](https://github.com/TheKoopaKingdom)
|
||||
|
||||
A lot of the questions we see on our Discord server all generally have the same answers; [missing system or font files](https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/), [missing config file](https://citra-emu.org/wiki/dumping-config-savegame-from-a-3ds-console/), an incorrectly dumped [game](https://citra-emu.org/wiki/dumping-installed-titles/) or [cartridge](https://citra-emu.org/wiki/dumping-game-cartridges/), or simply not having [modern enough hardware](https://citra-emu.org/wiki/faq/#what-kind-of-specification-do-i-need-to-run-citra) to run Citra. Because of this, [TheKoopaKingdom](https://github.com/TheKoopaKingdom) has written a patch to auto-detect these problems, report them to the user, and link them to a guide that will help them fix it, all without human intervention!
|
||||
|
||||
## [citra-qt: game list search function](https://github.com/citra-emu/citra/pull/2673) by [nicoboss](https://github.com/nicoboss)
|
||||
|
||||
For people with a lot of games, this new feature allows users to search through the entire list instead of having to browse. It works by checking to see if any games have any words the user typed in the search box. It's a bit naïve as of this point, but at least there is something to improve now. Maybe you could help improve this?
|
||||
|
||||
## [Kernel: Map special regions according to ExHeader](https://github.com/citra-emu/citra/pull/2687) by [yuriks](https://github.com/yuriks)
|
||||
|
||||
3DS binaries all have an extended header (or ExHeader) that specifies certains things about the application such as what permissions it has to access system services, and what hardware memory can it access. Basically all titles only accessed and mapped memory in almost the same way; read-only access to video memory, and read+write access to two specific sections of the sound hardware.
|
||||
|
||||
Because of this, Citra used to simply ignore the ExHeader, give it the same map as every other title, and give it access to everything. But now, it will actually parse the ExHeader and map memory regions as specified. This is why ROMs created with braindump don't work anymore, since braindump leaves the map empty, and Citra assumes that the title simply doesn't need access to anything, making them crash or behave very strangely.
|
||||
|
||||
As a side-effect, [yuriks](https://github.com/yuriks) also had to implement the entire memory map of the audio hardware, and took the opportunity to implement the New 3DS' extended memory, which New 3DS exclusives like Xenoblade Chronicles 3D require. Although this doesn't affect much in terms of game compatibility, Citra now emulates the kernel more accurately, and is now more prepared to handle exotic memory maps, like the ones used in system modules.
|
||||
|
||||
## Implement Various Fragment Lighting Features ([this](https://github.com/citra-emu/citra/pull/2727), [here](https://github.com/citra-emu/citra/pull/2762), and [there](https://github.com/citra-emu/citra/pull/2776)) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
These new features are all just features that were not known or not researched enough when the original lighting implementation was written. A few small fixes lead to big changes, such as the fact that Super Smash Bros. for 3DS now has proper lighting, instead of colours looking washed out and very bright.
|
||||
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-june/frag-light-before.png"
|
||||
alt="Super Smash Bros. for 3DS before the new lighting features" >}}
|
||||
|
||||
<!--
|
||||
title_id = 00040000000edf00
|
||||
commit_hash = bae3799bd5208d08bb52546ad0723103c94cada3
|
||||
-->
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-june/frag-light-after.png"
|
||||
alt="Super Smash Bros. for 3DS after the new lighting features"
|
||||
title="Finally someone turned down the lights." >}}
|
||||
|
||||
<!--
|
||||
title_id = 00040000000edf00
|
||||
commit_hash = c017065570f9bad90a8cd3dadac9b63d810793a6
|
||||
-->
|
||||
|
||||
## [Frontend: Prevent FileSystemWatcher from blocking UI thread](https://github.com/citra-emu/citra/pull/2669) by [jroweboy](https://github.com/jroweboy)
|
||||
|
||||
Recently [jroweboy](https://github.com/jroweboy) silently added a feature that allowed Citra to automatically refresh the game list when the game folder changes, so that restarting Citra was not necessary in order to see newly added games. The way this works is by creating a `FileSystemWatcher` for the configured game folder, and for every folder within it. This also means that if you were to set the games folder to something like, say, your home folder, Citra would become completely unresponsive while it created watchers for every single folder inside it. This little change adds a seperate thread that runs alongside the UI renderer, that searches the file tree, and when it's done, it hands off the list of folders to the UI thread, which adds them all to a single watcher. Although this does still cause a tiny bit of unresponsiveness when adding all the folders to the watcher, it's significantly less than it was before.
|
||||
|
||||
## Contributors of June 2017
|
||||
|
||||
It has been absolutely amazing to see so much work be put in by people from all over the world, in ever-increasing rates. I never thought that we would get to the point where tripling the rate at which these reports are published would be warranted, but here we are. And though the work will only get harder, I absolutely welcome more people wanting to help make this the best emulator it can be.
|
||||
|
||||
Although this progress report was a bit bare than most, the majority of it was cut due to lots of changes being either internal or only a fraction of something much bigger. Nevertheless, stay tuned on our [blog](https://citra-emu.org/), our [forums](https://community.citra-emu.org/), our [Twitter](https://twitter.com/citraemu), and our [Discord server](https://citra-emu.org/discord/) for the next few months, as we have some very big™ things planned.
|
||||
|
||||
As always, thank [you all](https://github.com/citra-emu/citra/graphs/contributors?from=2017-04-16&to=2017-07-10n&type=c) very much for taking the time to work on Citra, and helping it become what is has, and will be.
|
|
@ -20,10 +20,7 @@ Citra's video code has grown organically from the start; not much was known abou
|
|||
|
||||
The entire architecture of the 3DS was largely unknown, so development was done in small seperate bits at a time, and then trying to piece it all together into one cohesive piece of software. But, over time, as new pieces of information were found, the assumptions that were made previously broke. Some assumptions were very large, obvious, and easy to overcome, but a more subtle error that these assumptions created were not even in the design of the GPU, but rather the architecture and organization of the code itself.
|
||||
|
||||
<p style="text-align: center;">
|
||||
<img alt="" src="/images/entry/citra-progress-report-2017-p1/acnl-bridge.png" />
|
||||
Shouldn't there be a bridge here?
|
||||
</p>
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-p1/acnl-bridge.png" title="Shouldn't there be a bridge here?" alt="Animal Crossing bridge" >}}
|
||||
|
||||
The video code was very interconnected using this interface, so despite people being aware of this, it was also extremely difficult to move code around and reorganize it, as it could very easily affect unrelated bits of code that depended on it. This was only compounded by the hardware renderer, as it was written much like earlier, slowly adding hardware support bit-by-bit to separate parts of the video code, simply falling back into the software renderer when disabled or not supported.
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
+++
|
||||
date = "2018-02-04T17:00:00-04:00"
|
||||
title = "Citra Progress Report - 2017 Q4"
|
||||
tags = [ "progress-report" ]
|
||||
author = "anodium"
|
||||
forum = 9777
|
||||
+++
|
||||
|
||||
New year, new changes in Citra. Specifically, lots of technical changes under
|
||||
the hood, from applets to IPC, have made Citra even more accurate and laid a
|
||||
foundation for even more goodies the next year. With many great changes all
|
||||
around, this article is going to be packed to the brim with all the new goodies
|
||||
that have come to Citra during those crimson months.
|
||||
|
||||
But, enough faffing about! Let's get right into it:
|
||||
|
||||
## [citra-qt : Adding fullscreen mode](https://github.com/citra-emu/citra/pull/3001) by [Styleoshin](https://github.com/Styleoshin)
|
||||
|
||||
One of the most requested features for Citra has been enlarging the window to
|
||||
cover the entirety of the screen. After almost a year of requests on both the
|
||||
Citra Discourse and Discord servers, [Styleoshin](https://github.com/Styleoshin)
|
||||
has finally delivered!
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/fullscreen.png"
|
||||
title="No more pesky window décor!" >}}
|
||||
|
||||
Simply go into `View → Fullscreen`, or just strike the Alt + Return keycombo, and
|
||||
enjoy Citra to its fullest on your largest monitor.
|
||||
|
||||
## Rewrite AM Service and Add CIA Installation ([Here](https://github.com/citra-emu/citra/pull/2993), [here](https://github.com/citra-emu/citra/pull/3048), [here](https://github.com/citra-emu/citra/pull/2975), [there](https://github.com/citra-emu/citra/pull/3029), [this](https://github.com/citra-emu/citra/pull/3113), and [that](https://github.com/citra-emu/citra/pull/3144)) by [shinyquagsire23](https://github.com/shinyquagsire23) and [BreadFish64](https://github.com/BreadFish64)
|
||||
|
||||
The `am` service on a Nintendo 3DS handles the installation, tracking, and removal
|
||||
of applications and games installed on the console and SD card(s) via a centralized
|
||||
database in the NAND, with some parts of the database for SD card-installed titles
|
||||
on the SD card itself. It has a handful of nice features such as installing packages
|
||||
as they're streamed in, along with DLC support being cleanly implemented as a
|
||||
side-effect of the CIA format's design. CIAs themselves are also designed to be
|
||||
streamed in, which is used extensively across 3DS apps, such as the eShop streaming
|
||||
downloads directly into `am` so that it installs at the same time, or `dlp` using
|
||||
it to stream Download Play CIAs from one 3DS to another directly.
|
||||
|
||||
The CIA format starts off with a header that describes where each component of
|
||||
itself starts within the stream and a bitfield. This is then followed by a
|
||||
certificate signed by Nintendo, the CIA's ticket, and the title metadata (or TMD
|
||||
for short). The TMD then contains a list of every CXI file the CIA could possibly
|
||||
have, along with their name, size, etc.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/oot3dcia.png"
|
||||
title="A diagram of *The Legend of Zelda: Ocarina of Time 3D*'s CIA" >}}
|
||||
|
||||
The astute reader might've noticed I said that the TMD contains a list of every
|
||||
*possible* CXI. This is because a CIA might not contain every CXI for the game,
|
||||
such as in the case of DLC. The bitfield I mentioned in the header is used to list
|
||||
off which of the entries in the TMD actually exists within that CIA. This is
|
||||
(ab)used in some cases, such as the Home Menu Themes, in that every single theme
|
||||
that exists is actually a different CXI within the same CIA. Just tick the themes
|
||||
the user owns in the bitfield and then attach those CXIs at the end of it. Dead
|
||||
simple way for it to work perfectly with both streaming of the file, and making
|
||||
personalized CIAs for each eShop user.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/menucia.png"
|
||||
title="A tiny portion of the Home Menu Themes CIA" >}}
|
||||
|
||||
For the `am` side of streaming installations, the way it handles a request to
|
||||
install an application is by creating and then giving the requester a handle to
|
||||
a virtual file. This leaves most of the busy work to `am`, while the app only needs
|
||||
to worry about writing the CIA file into that handle.
|
||||
|
||||
[shinyquagsire23](https://github.com/shinyquagsire23) reimplemented the entirety
|
||||
of how Citra handles NCCH files, which quickly paved the way to implementing `am`
|
||||
in Citra. This allowed users to use FBI to install applications from its virtual
|
||||
SD card. He and [BreadFish64](https://github.com/BreadFish64) also went a step
|
||||
further and added support for installing CIAs via the SDL and Qt frontends
|
||||
directly, removing the need to use FBI. Do note that you cannot yet run installed
|
||||
applications and games directly, but CXI executables can access the virtual SD
|
||||
card for DLC, updates, etc.
|
||||
|
||||
## [Qtifw build installer](https://github.com/citra-emu/citra/pull/2966) by [j-selby](https://github.com/j-selby)
|
||||
|
||||
Citra now has a fancy new installer and updater, thanks to [j-selby](https://github.com/j-selby)
|
||||
and [jroweboy](https://github.com/jroweboy)'s efforts! If you haven't already, we
|
||||
strongly recommend you download and install Citra through it, since it will make
|
||||
updating as easy as re-running the installer. You can check it out over [here](/download/),
|
||||
|
||||
## [macOS: Build x86_64h slice](https://github.com/citra-emu/citra/pull/2982) by [MerryMage](https://github.com/MerryMage)
|
||||
|
||||
A little known feature in macOS is fat binaries, the ability to have the same executable
|
||||
contain binaries for multiple architectures. This was used extensively around 2007
|
||||
to support Mac OS X's transition from PowerPC to x86_64, allowing developers to
|
||||
have one binary work on all Macs effortlessly.
|
||||
|
||||
After poking around Apple's LLVM fork, [MerryMage](https://github.com/MerryMage)
|
||||
found that they had a specific flag to build binaries for Intel Haswell and later.
|
||||
Enabling it made a fat binary that contained both pre-Haswell and post-Haswell code,
|
||||
allowing Citra to take advantage of the newer CPU's instructions, without dropping
|
||||
support for older ones.
|
||||
|
||||
## [Kernel/IPC: Add a small delay after each SyncRequest to prevent thread starvation.](https://github.com/citra-emu/citra/pull/3091) by [Subv](https://github.com/Subv)
|
||||
|
||||
When communicating with services, titles on a real Nintendo 3DS expect to wait some
|
||||
amount of time before the service replies or responds. Until now, Citra didn't implement
|
||||
this, it responded without incrementing the virtual clock. From the emulated system's
|
||||
perspective, it appeared as though services replied and responded literally instantly
|
||||
because of this, leading to strange side-effects.
|
||||
|
||||
For example, some buildings in *Animal Crossing: New Leaf* fail to render and
|
||||
cannot be interacted with.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/acnl-before.png"
|
||||
title="Animal Crossing: New Leaf's acting up" >}}
|
||||
|
||||
Or worse, some games such as *Star Fox 3D* can't even
|
||||
reach the title screen.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/fsUSER-threads.png"
|
||||
title="A demonstration of how instant service replies can break a title" >}}
|
||||
|
||||
The example in this figure is taken directly from *Star Fox 3D*. When the game boots,
|
||||
it checks if any save data exists on the console's SD card, and tries to recreate it
|
||||
if it doesn't. It does this by sending a request to the service responsible for
|
||||
file access, and then waiting for a reply. Because the request is synchronous,
|
||||
the thread that made the request is put to sleep and its priority lowered. The
|
||||
game actually uses this time that would otherwise be spent waiting by having other
|
||||
threads run while the original thread was still asleep, so that by the time it
|
||||
woke up with the response, it would have other resources it needed ready to go.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/acnl-after.png"
|
||||
title="Animal Crossing: New Leaf, among other games, are now working perfectly with this change!" >}}
|
||||
|
||||
As Citra's responses are instantaneous from the point-of-view of the game,
|
||||
the secondary thread doesn't have nearly enough time to finish its job. And, the
|
||||
first thread's priority comes back up above the secondary's once it wakes up,
|
||||
this leads to the first thread waiting on the secondary thread to finish, but it
|
||||
never gets a chance to, due to its now much lower priority. Essentially, the
|
||||
first thread waits on the secondary forever, because the secondary never gets a
|
||||
chance to actually finish what it was doing.
|
||||
|
||||
[ds84182](https://github.com/ds84182) and [Subv](https://github.com/Subv) each
|
||||
wrote homebrew software which found and measured the issue, respectively, which
|
||||
[B3n30](https://github.com/B3n30) ran on a real Nintendo 3DS. With which, an
|
||||
average delay for every type of service reply was found. Then, [Subv](https://github.com/Subv)
|
||||
made Citra's virtual clock increment by this amount before fulfilling any service
|
||||
request, solving many of the issues this brought.
|
||||
|
||||
## [core/arm: Improve timing accuracy before service calls in JIT](https://github.com/citra-emu/citra/pull/3184) by [MerryMage](https://github.com/MerryMage)
|
||||
|
||||
As our previous section demonstrates, Citra's virtual clock should be
|
||||
incremented before any time code that was supposed to be on a real
|
||||
Nintendo 3DS runs within Citra, including services. This change by [MerryMage](https://github.com/MerryMage)
|
||||
makes services increment the clock *before* they are called, instead of after.
|
||||
|
||||
<!-- NOTE: Possibly hard to understand/too verbose? Reword if so. -->
|
||||
One of the reasons this is important is that services can schedule calls to
|
||||
other services to run in the future. If the current time in the virtual clock is
|
||||
incorrect when the service schedule an event, it would run too early since
|
||||
the time for the scheduled event would effectively be shifted back by the virtual
|
||||
time it takes for the service that scheduled it would run.
|
||||
|
||||
Although this doesn't fix any reported bugs, it does make the timing emulation
|
||||
of Citra much more accurate.
|
||||
|
||||
## [citra-qt : Fix a bug in our fullscreen implementation](https://github.com/citra-emu/citra/pull/3159) by [FearlessTobi](https://github.com/FearlessTobi)
|
||||
|
||||
In Citra's GUI, a strange bug exists, where if you have fullscreen enabled, and
|
||||
you start a game while the window is maximized, the window instead unmaximizes
|
||||
before starting the game. This was due to Citra not keeping track of the window's
|
||||
state (be it normal, maximized, minimized, or fullscreen), and instead simply
|
||||
defaulting to normal. [FearlessTobi](https://github.com/FearlessTobi) found,
|
||||
[reported](https://github.com/citra-emu/citra/pull/3001#issuecomment-338401048),
|
||||
and fixed the bug. Citra now keeps track of the window's state, position, and
|
||||
size, every time it goes fullscreen and restores them every time it leaves
|
||||
fullscreen.
|
||||
|
||||
## [Allow input configuration with SDL joysticks](https://github.com/citra-emu/citra/pull/3116) by [muemart](https://github.com/muemart)
|
||||
|
||||
In the input configuration menu, there has been the ability to change the key
|
||||
bindings on the keyboard for years now. Unfortunately, this menu allowed rebinding
|
||||
to keyboard keys only, not gamepads or any other input device one could use. This
|
||||
led to guides such as [this one](https://community.citra-emu.org/t/temporary-controller-configurations-for-citra/1061)
|
||||
being written, to help users manually change the configuration files if they
|
||||
wanted to use gamepads with Citra.
|
||||
|
||||
This was extremely inconvenient and user-unfriendly to most, and so [muemart](https://github.com/muemart)
|
||||
took it upon themselves to finally add support for configuring gamepads within the
|
||||
configuration menu. Now, it's as simple as clicking a button, and pressing the
|
||||
corresponding button on your controller, to set it up.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/controller.png"
|
||||
title="Citra's input configuration menu" >}}
|
||||
|
||||
## [shader_jit_x64_compiler: Remove ABI overhead of LG2 and EX2](https://github.com/citra-emu/citra/pull/3145) by [MerryMage](https://github.com/MerryMage)
|
||||
|
||||
The shader JIT in Citra is a component of the video core responsible for
|
||||
recompiling GPU shaders for the 3DS to x86 code, so that they can be run on the
|
||||
user's CPU directly.
|
||||
|
||||
Shader instructions like LG2 (calculate binary logarithm) and EX2 (calculate binary
|
||||
exponential) can be run potentially thousands of times per second in a typical
|
||||
Nintendo 3DS title, so it's usually very worthwhile to try to optimize these as
|
||||
best as possible.
|
||||
|
||||
In doing so, [MerryMage](https://github.com/MerryMage) actually rewrote these two
|
||||
instructions to pure x86 assembly, and runs them inline with the rest of the instructions.
|
||||
A faster algorithm, combined with not having to deal with the overhead of calling
|
||||
an external library for math functions, led to this change almost halving the
|
||||
amount of time it takes to calculate these!
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/shaderjit.png"
|
||||
title="Graph comparing times before and after this change" >}}
|
||||
|
||||
## Conclusion
|
||||
|
||||
As always, [changes big or small](https://github.com/citra-emu/citra/graphs/contributors?from=2017-10-01&to=2017-12-31&type=c)
|
||||
are vital to the project. Brick by brick, Citra will eventually be an accurate enough
|
||||
emulation of the Nintendo 3DS for most, if not all, uses. Thank you everyone for
|
||||
the hard work you've poured in.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-q4/promo.png"
|
||||
title="And more to come." >}}
|
|
@ -0,0 +1,361 @@
|
|||
+++
|
||||
date = "2017-11-09T09:46:00-04:00"
|
||||
title = "Citra Progress Report - 2017 September"
|
||||
tags = [ "progress-report" ]
|
||||
author = "anodium"
|
||||
forum = 5005
|
||||
+++
|
||||
|
||||
Winter arrives once more, and like I mentioned in [August's progress report](/entry/citra-progress-report-2017-august),
|
||||
I am extremely excited for what's in store. In fact, many of the really big goodies
|
||||
I've decided to seperate to their own articles, which should be coming up in the
|
||||
next few weeks.
|
||||
|
||||
There's also been many changes this month that improve the speed of emulation across
|
||||
the board, on top of the usual improvements in accuracy and features. And because
|
||||
of that, I've dubbed this month #Speedtember. Let's dive right in.
|
||||
|
||||
{{% callout %}}
|
||||
Hello everyone! We're all terribly sorry for the delay in getting this progress
|
||||
report out the door, but our main technical writer [anodium](https://github.com/anodium),
|
||||
was just a bit busy surviving both Hurricane Irma and Maria. Although she's a
|
||||
trooper and claims it's not an excuse for the delay, we find that her personal
|
||||
safety is a tad more important. We're all glad that she's safe and sound, and in
|
||||
a state where she can keep pumping out quality articles for Citra!
|
||||
{{% /callout %}}
|
||||
|
||||
## [Switchable Page Tables](https://github.com/citra-emu/citra/pull/2952) by [MerryMage](https://github.com/MerryMage)
|
||||
|
||||
Citra has a component called [dynarmic](https://github.com/MerryMage/dynarmic),
|
||||
which recompiles ARM11 code to x86-64 code at run time, and then executes that
|
||||
generated code, rather than interpreting the ARM11 instructions directly.
|
||||
|
||||
Because the 3DS has a 32 bit address bus, it can address 2^32 unique memory locations.
|
||||
And because the 3DS can address data down to a byte, it can address up to 2^32
|
||||
unique bytes, or about 4 gigabytes of memory. When considering that no 3DS has ever
|
||||
been released with more than 256 *mega*bytes of memory, this sounds absurd! And
|
||||
it is... unless you consider that a 3DS uses chunks of that huge address space to
|
||||
address peripherals, among other things. This is called memory-mapped input/output
|
||||
(MMIO), and is a great use of millions of addresses that would otherwise have
|
||||
been ignored, plus it also allows handling IO the exact same way memory is handled,
|
||||
so the design can be a bit simpler as it doesn't need special circuitry to handle IO.
|
||||
|
||||
Herein lies our problem. Because that code is now being run on a PC, those MMIO
|
||||
devices don't actually exist anymore, so Citra needs to handle those reads and
|
||||
writes itself. There's a few ways to go about it, but the simplest and most naïve
|
||||
is to replace every memory read or write with a function that checks if that address
|
||||
is mapped to memory or IO. Unfortunately, this is extremely slow, and we can't
|
||||
afford to have extremely slow address translation when games can access memory
|
||||
upwards of a few hundred thousand times per second.
|
||||
|
||||
With this, [MerryMage](https://github.com/MerryMage) has changed this behaviour so
|
||||
that rather than replacing a read/write with a function, it instead translates the
|
||||
address using a page table, and then tries to access that address directly. On the
|
||||
page table, all addresses that map to memory simply have a memory address written down.
|
||||
But on addresses that map to IO, it has address 0 written down. Trying to read or
|
||||
write to memory address 0 on x86 is illegal for every process except the
|
||||
operating system... and Citra tries to do it anyways!
|
||||
|
||||
When an invalid memory address (or a memory address that that process doesn't have
|
||||
permission to access) is read from or written to, x86 CPUs throw a page fault exception.
|
||||
Citra takes advantage of this behaviour by also registering an exception handler
|
||||
for page faults. If a page fault is thrown, Citra knows the game tried to access IO,
|
||||
and thus recompiles the memory read/write to a direct call to Citra's IO functions.
|
||||
This makes the usual case (memory access) extremely fast, and the less usual case
|
||||
slow, but only the first time it happens. Subsequent IO accesses use the recompiled
|
||||
functions which are faster.
|
||||
|
||||
This technique is called fastmem, and is not new at all. In fact, Dolphin uses
|
||||
it extensively in its JIT recompiler to speed up memory access as well. And thanks
|
||||
to [MerryMage](https://github.com/MerryMage)'s hard work, this same technique is
|
||||
now used extensively by Citra.
|
||||
|
||||
## [Give each process its own page table](https://github.com/citra-emu/citra/pull/2842) by [Subv](https://github.com/Subv)
|
||||
|
||||
In order to support running multiple processes at the same time, like your computer,
|
||||
Citra implements virtual memory, in which each process has its own page table.
|
||||
The page table represents a translation from the process' virtual addresses, to
|
||||
the 3DS' physical (or "real") addresses.
|
||||
|
||||
Before this, because Citra did not support multiple page tables, it also didn't
|
||||
support running multiple processes at once, such as a game and the software keyboard
|
||||
applet. Now, thanks to [Subv](https://github.com/Subv), Citra has an important
|
||||
building block in place.
|
||||
|
||||
## [Add support for loading application updates](https://github.com/citra-emu/citra/pull/2927) by [shinyquagsire23](https://github.com/shinyquagsire23)
|
||||
|
||||
Nintendo 3DS titles are contained within `*.app` files on the SD card or on the
|
||||
game cartridge, in the [NCCH container format](https://www.3dbrew.org/wiki/NCCH).
|
||||
This format is further divided into two formats, CXI and CFA, which stand for
|
||||
__C__TR e__X__ecutable __I__mage and __C__TR __F__ile __A__rchive, respectively.
|
||||
CXIs contain executable code, whereas CFAs cannot. CFAs usually accompany a CXI
|
||||
to provide other features such as the digital instruction manual, the Download Play
|
||||
child application, or in the case of game cartridges, system updates.
|
||||
|
||||
Both types of NCCH start with a header, and then followed by either an ExeFS
|
||||
image, a RomFS image, or both. The entire structure of an NCCH header may be best
|
||||
explained by a diagram:
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-september/ncch.png"
|
||||
title="Solid lines are required sections, dashed lines cannot be used in some cases, and dotted lines are optional sections." >}}
|
||||
|
||||
Now, games and applications need updates from time to time, and 3DSes handle these
|
||||
by installing the update as a seperate title from the base game. From that point
|
||||
on, whenever the user tries to launch the game, instead of loading the
|
||||
extended header (or [ExHeader](https://www.3dbrew.org/wiki/ExHeader) for short)
|
||||
and ExeFS image from the base game's NCCH, it replaces them with the update's
|
||||
ExHeader and ExeFS on launch. As for RomFS, the 3DS System Software will actually
|
||||
load both the base game's and the update's RomFS image, rather than replacing one
|
||||
with the other. Games are left to their own devices on how to handle these, and
|
||||
so the methods used per game can vary, though they usually just replace changed
|
||||
files, picking files from the base game RomFS if they haven't been modified.
|
||||
|
||||
Citra, before this PR, had the code for loading games and reading NCCH files all
|
||||
mixed into one big piece that fit in with everything else. With this patch,
|
||||
[shinyquagsire23](https://github.com/shinyquagsire23) has seperated the loader
|
||||
from the NCCH reader, allowing the loader to read multiple NCCHs at once. Additionally,
|
||||
whenever a game is loaded, the loader would also check if there is an update title
|
||||
installed on Citra's [virtual SD card](/wiki/user-directory/). If there is, it
|
||||
would replace the update ExHeader and ExeFS, and load the update RomFS as well.
|
||||
Just like a real console!
|
||||
|
||||
Most games worked out of the box with updates, and because they wrote the code
|
||||
with accuracy in mind, this very same PR has also laid part of the foundation
|
||||
needed to handle other features such as DLC support or even using real 3DS SD cards!
|
||||
Though, do note that we don't have any estimates on either those or any other
|
||||
features, as no one is actively working on either.
|
||||
|
||||
## [Implement geometry shader](https://github.com/citra-emu/citra/pull/2865) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
The PICA200 GPU has a pipeline similar to [OpenGL's pipeline](https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview)
|
||||
for rendering 3D objects into a 2D display. I won't go through them all here,
|
||||
only the optional geometry shader step. Just after the vertex shader step, if
|
||||
enabled, all the vertices are processed by a shader kernel (which is a small
|
||||
program that runs directly on a GPU), taking as many vertices as the kernel
|
||||
wants as input, and outputting as many vertices as the kernel wants.
|
||||
|
||||
Because the kernel in the geometry shader is allowed as many inputs and outputs
|
||||
as it wants, it is significantly more powerful and flexible than the vertex shader,
|
||||
whose kernel is restricted to only one vertex at a time, both for input and output.
|
||||
But for that same reason, geometry shaders are much more complex to program, and
|
||||
so many games simply disable it. The games that do not disable it though, tend to
|
||||
use it very extensively, to the point of completely breaking graphics if it's not
|
||||
implemented.
|
||||
|
||||
Multiple uses have been found in the wild for geometry shaders, including but absolutely
|
||||
not limited to:
|
||||
|
||||
- Taking one vertex as input, and outputting a rectangle of vertices which can
|
||||
be textured with a sprite. Pokémon uses this extensively to render particles
|
||||
whenever a move is used. Monster Hunter takes it a step further and renders
|
||||
*all of its HUD and GUI* with this kernel.
|
||||
|
||||
- Taking a handful of vertices as input, and outputting even more vertices which
|
||||
are interpolations between the inputs, thus making the resulting mesh look smoother
|
||||
and less jagged when rendered.
|
||||
|
||||
At first glance, geometry shaders looked like an easy problem, since they use the
|
||||
same instruction set and format as vertex shaders, so a lot of the same code could
|
||||
be reused. At *second* glance, it turned out that configuring inputs and outputs
|
||||
for geometry shaders is much more complex than it is for vertex shaders.
|
||||
|
||||
There were actually three attempts to implement geometry shaders in Citra. The first
|
||||
was written by [ds84182](https://github.com/ds84182) about two years ago, only to
|
||||
be abandoned due to not knowing how the configuration of them was done. The second
|
||||
attempt was written by [JayFoxRox](https://github.com/JayFoxRox), but was also
|
||||
abandoned for the same reason.
|
||||
|
||||
But, after extensive research on geometry shaders was made by [fincs](https://github.com/fincs),
|
||||
the API was implemented in [ctrulib](https://github.com/smealum/ctrulib) and
|
||||
[citro3d](https://github.com/fincs/citro3d), and examples were written to demonstrate
|
||||
how to use it. Now that the community knew exactly how they worked, [wwylele](https://github.com/wwylele)
|
||||
picked up where [JayFoxRox](https://github.com/JayFoxRox) left off, cleaned up
|
||||
the code he wrote, and added the missing pieces.
|
||||
|
||||
After almost three years, and three different attempts to make it work, Citra now
|
||||
has a full, complete, and correct implementation of geometry shaders!
|
||||
|
||||
## [Implement custom clip plane](https://github.com/citra-emu/citra/pull/2900) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
After the geometry shader (or the vertex shader, if it wasn't enabled), the vertices
|
||||
are "assembled" into a collection of triangles. After *that*, to make rendering
|
||||
more efficient, the triangles are then compared to 6 planes that make up the cube
|
||||
in which objects are actually visible by the camera. Any triangles outside of that
|
||||
cube are deleted, and any triangles that are partially inside the cube are split
|
||||
by the sides of the cube, and the resulting triangle outside of the cube is also
|
||||
deleted.
|
||||
|
||||
But the 3DS allows games to add a 7th plane whose position is fully customizable.
|
||||
Although no games are known to use this feature right now, it is indeed a feature
|
||||
of the 3DS' GPU. Because implementing it was fairly straightforward,
|
||||
[wwylele](https://github.com/wwylele) decided to just go ahead and implement it,
|
||||
in case someone decided to use it in the future.
|
||||
|
||||
## [Optimized Morton](https://github.com/citra-emu/citra/pull/2951) by [huwpascoe](https://github.com/huwpascoe)
|
||||
|
||||
Morton code is a function that interleaves multi-dimensional numbers into a one-dimensional
|
||||
number. Although it may seem like a very esoteric function, it's actually extremely
|
||||
useful in fields like linear algebra, databases, and what the 3DS uses it for:
|
||||
texture mapping.
|
||||
|
||||
Computers have an intermediate chunk of memory between RAM and the CPU called a
|
||||
cache. Caches are seperated into lines, each of which can hold one data item. GPUs
|
||||
also have a cache, also seperated into lines. Because they are seperated like this,
|
||||
if a texture is loaded into the cache, it would have to span multiple cache lines,
|
||||
or even not fit into the cache completely, thus making transformations on it slow,
|
||||
as it would have to load and store pieces of it from RAM multiple times.
|
||||
|
||||
To avoid this, GPUs can Morton encode textures so that two-dimensional manipulations
|
||||
are more likely to only need data already in the cache. Textures that have been
|
||||
Morton coded are usually referred to as swizzled or twiddled textures.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2017-september/morton-koopa.png#floatright"
|
||||
title="Not this Morton!" >}}
|
||||
|
||||
In the function that Morton is implemented, there was a lookup table on Morton
|
||||
codes in the comments, and [huwpascoe](https://github.com/huwpascoe) thought it'd
|
||||
be best if we just use the lookup table directly. It worked just as well as before,
|
||||
but required less than a third of the math. Because this function is called so
|
||||
often during emulation (a rough estimate from them is about "millions of times a
|
||||
second"), this change although small, made very big changes in CPU performance.
|
||||
|
||||
## [Add draw for immediate and batch modes](https://github.com/citra-emu/citra/pull/2921) by [jroweboy](https://github.com/jroweboy)
|
||||
|
||||
The 3DS' GPU has two main modes for drawing to the screen, immediate and batch
|
||||
mode. In the former, the GPU takes and immediately draws every vertex as it is
|
||||
handed to it. In the latter, the GPU accepts vertices given to it, but doesn't
|
||||
actually bother drawing them until absolutely necessary, saving a bit of time
|
||||
from not having to go through the drawing procedure for every individual vertex.
|
||||
Although most games don't use immediate mode at all due to it being extremely
|
||||
slow, a handful do use it for a handful of visual effects, like New Super Mario
|
||||
Bros. 2.
|
||||
|
||||
About a year ago when the GPU code on Citra was rewritten, a handful of calls to
|
||||
the drawing routine were removed, as it was believed they were unnecessary. Turns
|
||||
out, one of the calls was actually needed for some effects in games, as it handled
|
||||
immediate mode drawing. This wasn't noticed for a very long time, as most games
|
||||
appeared to carry on with no side-effects at all from the rewrite, but was eventually
|
||||
found after some research courtesy of [ds84182](https://github.com/ds84182).
|
||||
|
||||
## [Interpolate audio samples on a frame-by-frame basis](https://github.com/citra-emu/citra/pull/2858) by [MerryMage](https://github.com/MerryMage)
|
||||
|
||||
When a 3DS game needs some sort of audio processing, they can access the 3DS' DSP,
|
||||
or __D__igital __S__ound __P__rocessor. It's another processor, alongside the ARM9
|
||||
and ARM11, that is given a firmware to run, which in turn is given a bunch of audio
|
||||
samples and parameters by the game. The DSP then plays back the buffer in chunks
|
||||
of about 5 milliseconds. Each one of these chunks is called an audio frame.
|
||||
|
||||
As of today, we don't know how the DSP exactly works, and we don't know how any
|
||||
of the firmwares exactly work. (Did I forget to mention earlier there's multiple
|
||||
versions of the firmware?) But we do know how to use it, and from there we can
|
||||
reimplement its behaviour directly in Citra. Which is exactly what [MerryMage](https://github.com/MerryMage)
|
||||
did back in June of 2016, which in turn brought [audio support for the first time](/entry/hle-audio-comes-to-citra/)
|
||||
in Citra.
|
||||
|
||||
This approach, although having the advantages of being easier to implement, easier
|
||||
to understand in code, and has a higher potential of being faster, it has the
|
||||
disadvantage that accuracy suffers significantly, especially when shortcuts are
|
||||
taken for the sake of speed. One of these shortcuts was in the audio interpolation,
|
||||
which is a way of inferring more audio samples from relatively very few existing
|
||||
samples.
|
||||
|
||||
On a real 3DS, games are allowed to interpolate different audio frames with
|
||||
different functions, even when in they're in the same buffer. On the other hand,
|
||||
Citra interpolated the entire buffer with one function as soon as it was loaded.
|
||||
This led to various effects and music in games to sound strange or inaccurate in
|
||||
some way.
|
||||
|
||||
One example of this is Deku Link's footsteps in *The Legend of Zelda: Majora's Mask 3D*.
|
||||
|
||||
Here's the output of a real 3DS console, for reference:
|
||||
|
||||
{{< audio src="/images/entry/citra-progress-report-2017-september/deku-hardware.ogg" >}}
|
||||
|
||||
And here's the output of Citra, before this was fixed:
|
||||
|
||||
{{< audio src="/images/entry/citra-progress-report-2017-september/deku-pre2858.ogg" >}}
|
||||
|
||||
Now that it's been fixed, his footsteps sound a lot better:
|
||||
|
||||
{{< audio src="/images/entry/citra-progress-report-2017-september/deku-post2858.ogg" >}}
|
||||
|
||||
Audio emulation in Citra is still somewhat inaccurate for now, though
|
||||
[MerryMage](https://github.com/MerryMage) is gradually working on fixing and
|
||||
improving it. Perhaps some day we may even be able to emulate the DSP firmware
|
||||
directly, which will be much more accurate than merely emulating its behaviour.
|
||||
|
||||
## [Use deque instead of vector for the audio buffer](https://github.com/citra-emu/citra/pull/2958) by [Subv](https://github.com/Subv)
|
||||
|
||||
Whenever the DSP consumes some frames from the audio buffer, Citra deletes them
|
||||
from it. This normally wouldn't pose any problems, but because the buffer was
|
||||
being stored as a vector, this led to some uneccessary operations. Namely, the
|
||||
C++ standard requires that all the data of a standard vector be in one contiguous
|
||||
block of memory. Because deleting frames from the buffer breaks this rule, Citra
|
||||
would automatically (1) allocate a new block of memory, (2) copy the entire buffer
|
||||
into that new block of memory, and (3) deallocate the old block of memory, thus
|
||||
deleting the old buffer.
|
||||
|
||||
These steps are huge waste of time, as Citra doesn't need to guarantee that the
|
||||
audio buffer is in one contiguous block. So [Subv](https://github.com/Subv) changed
|
||||
the type of the buffer from a vector to a deque, which is essentially a queue that
|
||||
you can remove data from both the beginning and end of it. Because the contiguity
|
||||
requirement doesn't exist in deques, Citra doesn't do the uneccessary copying,
|
||||
leading to huge speed boosts in audio bound titles like Super Mario 3D Land, and
|
||||
even the Home Menu. Now, both run significantly faster!
|
||||
|
||||
## [Add mingw64 compile support to appveyor](https://github.com/citra-emu/citra/pull/2912) by [jroweboy](https://github.com/jroweboy)
|
||||
|
||||
When a program is written in a high-level programming language, such as C++, Rust,
|
||||
or Go, before the program can be run on a machine, it must be translated or "compiled"
|
||||
to machine code. Although it is possible to do this translation by hand, it is
|
||||
usually extremely difficult to do so and very time consuming. So instead, we have
|
||||
a program called a compiler than can automatically do this translation for us.
|
||||
|
||||
This is also why a program compiled for an ARM machine cannot be run directly on
|
||||
an x86 machine, even when the source can work on either machine without issues.
|
||||
Instead this program must be translated, interpreted, or recompiled from source
|
||||
to x86. (In fact, this translation is exactly what [dynarmic](https://github.com/MerryMage/dynarmic)
|
||||
does to run code from a 3DS.)
|
||||
|
||||
Every statement in a program must have an exact, unambiguous definition of what
|
||||
it does (its semantics). But, in the same way that a statement that means one
|
||||
thing can be written many different ways, and different compilers can translate the
|
||||
same statement many different ways.
|
||||
|
||||
On Windows, there's two popular C++ compilers available as of today: MSVC++, which
|
||||
is the compiler Microsoft has written for Windows, and MINGW GCC, which is actually
|
||||
a port of the Linux `gcc` compiler to Windows. For better or worse, MINGW GCC
|
||||
optimizes Citra a little better than MSVC++, and so [jroweboy](https://github.com/jroweboy)
|
||||
has changed the Citra AppVeyor build script to add support for MINGW GCC as well
|
||||
as MSVC++. Do note that the MSVC++ builds are only available through GitHub, since
|
||||
they're only useful for debugging, and MINGW GCC builds are faster in most, if
|
||||
not all, cases, which is why the installer will only install those. This change
|
||||
also has closed the gap in performance the new Nightly builds had compared to
|
||||
the old Bleeding Edge builds.
|
||||
|
||||
## [Load different shared font depending on the region](https://github.com/citra-emu/citra/pull/2915) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
Remember that last month [wwylele](https://github.com/wwylele) changed Citra so
|
||||
that instead of loading the shared font from a seperate file, it would
|
||||
[load it from the system archive](https://citra-emu.org/entry/citra-progress-report-2017-august/)?
|
||||
This builds on top of that behaviour. You see, a 3DS doesn't have a shared font,
|
||||
it has *four*. One contains glyphs for Latin script (for English, Spanish, Italian,
|
||||
French, etc.) and Japanese scripts, another contains glyphs for Traditional Chinese,
|
||||
the third font contains those for Simplified Chinese, and the last font contains
|
||||
the ones for Korean.
|
||||
|
||||
Before this PR, Citra would simply load the first shared font regardless of game
|
||||
or region. This made non-Latin or non-Japanese script games display completely
|
||||
incorrect characters at best, or crash at worst. Now Citra will load the appropriate
|
||||
shared font from the system archive depending on the region selected, just like
|
||||
a real console! Though, this will not work on machines that only have the
|
||||
`shared_font.bin` file, because it only contains the shared font for the region
|
||||
of the console it was dumped from. (e.g.: If you dump a Korean console, it'll
|
||||
only contain the Korean font.) If you want to use this feature, you must dump
|
||||
the system archive using the latest version of [`3dsutils`](https://github.com/citra-emu/3dsutils).
|
||||
|
||||
## Et. al.
|
||||
|
||||
And of course, big thanks to [everyone who's contributed](https://github.com/citra-emu/citra/graphs/contributors?from=2017-08-31&to=2017-09-30&type=c)
|
||||
this September, because Citra as a whole would not be the same without everyone
|
||||
involved having placed their pieces, big or small.
|
|
@ -0,0 +1,236 @@
|
|||
+++
|
||||
date = "2018-05-30T19:30:00+05:30"
|
||||
title = "Citra Progress Report 2018 Q1"
|
||||
tags = [ "progress-report" ]
|
||||
author = "CaptV0rt3x"
|
||||
forum = 23597
|
||||
+++
|
||||
|
||||
It's been a while folks - since the last report, we have had many new features come to Citra. Some
|
||||
notable ones include multiplayer improvements, hardware shader improvements (post GLvtx), a logging
|
||||
system rewrite, and the highly coveted camera support. Our continuous integration (CI) systems were
|
||||
optimized as well. Apart from these, we have had many more minor features, improvements, and bug fixes.
|
||||
So, without further ado let's get right into it:
|
||||
|
||||
## citra-qt: Multiplayer Improvements ([here](https://github.com/citra-emu/citra/pull/3444), [there](https://github.com/citra-emu/citra/pull/3481), [this](https://github.com/citra-emu/citra/pull/3489), and [that](https://github.com/citra-emu/citra/pull/3676)) by [jroweboy](https://github.com/jroweboy) and [B3n30](https://github.com/B3n30)
|
||||
|
||||
Citra has been able to run many games at playable speeds for a while now. However, it was always lacking
|
||||
something which the 3DS has: the ability to play with friends. In order to make it a reality, our developers [jroweboy](https://github.com/jroweboy), [B3n30](https://github.com/B3N30), [Subv](https://github.com/subv),
|
||||
and [JayFoxRox](https://github.com/jayfoxrox) worked tirelessly for months to reverse engineer workings
|
||||
of the 3DS local wireless system. Thanks to their efforts, Citra now emulates _local wireless multiplayer_
|
||||
over the internet. This allows you to play your favorite games with your virtual friends across the world.
|
||||
Later [jroweboy](https://github.com/jroweboy), [B3n30](https://github.com/B3n30), and few others
|
||||
worked on various feature improvements and bug fixes.
|
||||
|
||||
### Features
|
||||
Currently, the multiplayer features include:
|
||||
|
||||
* We now have multiple servers, maintained by our very own [FlameSage](https://community.citra-emu.org/u/flamesage/summary)
|
||||
and many other community members at various locations around the globe, so that you can meet others
|
||||
online.
|
||||
* You can now create rooms which can hold up to 16 players and even secure them with a password.
|
||||
* You can now set a preferred game for your room.
|
||||
* You can also filter the servers to suit your needs.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q1/server-list.png"
|
||||
title="Sooo many servers to choose from!" >}}
|
||||
|
||||
Since its initial release in Canary, developers have listened to the community and have been trying
|
||||
very hard to fix bugs causing games to be incompatible. They have also added other features to make
|
||||
the multiplayer experience richer.
|
||||
|
||||
### Compatible Titles
|
||||
We are proud to announce that multiplayer currently works in the following list of titles:
|
||||
|
||||
* Dragon Quest Monsters: Joker 3 Professional
|
||||
* Luigi's Mansion: Dark Moon
|
||||
* Mario Party: The Top 100
|
||||
* Monster Hunter 3G & 3 Ultimate
|
||||
* Monster Hunter 4, 4G & 4 Ultimate
|
||||
* Monster Hunter X
|
||||
* Monster Hunter XX
|
||||
* New Super Mario Bros. 2
|
||||
* Pokémon Omega Ruby / Alpha Sapphire
|
||||
* Pokémon Sun / Moon
|
||||
* Pokémon Ultra Sun / Ultra Moon
|
||||
* Pokémon Virtual Console
|
||||
* Super Smash Bros.
|
||||
* The Legend of Zelda: Tri Force Heroes
|
||||
* And many more.
|
||||
|
||||
### Incompatible Titles
|
||||
For various reasons, the following games were tested and do not work:
|
||||
|
||||
* Asphalt Assault 3D
|
||||
* Code of Princess (*a fix is in works*)
|
||||
* Dragon Quest Monsters: Terry's Wonderland 3D
|
||||
* F1 2011
|
||||
* Kirby Fighters Deluxe
|
||||
* Kirby Triple Deluxe
|
||||
* Mario Party Island Tour
|
||||
* Mario Party Star Rush
|
||||
* Mario Kart 7
|
||||
* Planet Crashers
|
||||
* Resident Evil: The Mercenaries 3D
|
||||
* Ridge Racer 3D
|
||||
* Sonic Generations
|
||||
* Street Fighter IV
|
||||
* Tetris Ultimate
|
||||
|
||||
***Note that this list isn't absolute, and multiplayer may or may not work in games not listed here.
|
||||
Also note that Download Play and Spotpass titles do not work as they are beyond the scope of current
|
||||
local multiplayer***.
|
||||
|
||||
Although multiplayer is supported, some games might still experience issues with it. Since the servers
|
||||
are located in various locations, latency will play a major role in your gameplay experience, so always
|
||||
choose a server that is nearby (geographically). Please use our [support forums](https://community.citra-emu.org/),
|
||||
[IRC](http://webchat.freenode.net/?channels=citra), or [Discord](https://citra-emu.org/discord/) for
|
||||
help regarding issues with multiplayer.
|
||||
|
||||
Read more about the multiplayer feature update [here](https://citra-emu.org/entry/announcing-networking-support/).
|
||||
|
||||
## citra-qt: Hardware Shader Improvements (post GLvtx) by [wwylele](https://github.com/wwylele) and [degasus](https://github.com/degasus)
|
||||
|
||||
Citra has come a long way from just being able to render graphics in 2015, to being able to run games
|
||||
at a playable state. Still, Citra was only fast for users who had better hardware. Users with slower
|
||||
processors suffered from lag and stuttering during gameplay.
|
||||
|
||||
Now, thanks to the combined efforts of [phantom](https://github.com/phanto-m), [jroweboy](https://github.com/jroweboy), [wwylele](https://github.com/wwylele), [MerryMage](https://github.com/MerryMage), and many more, we
|
||||
now have a near-complete hardware renderer with huge improvements. Citra now uses the host GPU to its
|
||||
fullest to render graphics. [wwylele](https://github.com/wwylele) and [MerryMage](https://github.com/MerryMage)
|
||||
took it upon themselves to simplify the humongous heap of code into smaller parts, fixing, and testing
|
||||
them.
|
||||
|
||||
Thanks to [degasus](https://github.com/degasus) from the Dolphin community, who imparted his valuable
|
||||
knowledge and understanding of GPUs and OpenGL, we were able to optimize the _streaming storage buffer_
|
||||
support added by [phantom](https://github.com/phanto-m). This was done entirely by [degasus](https://github.com/degasus)
|
||||
himself ([here](https://github.com/citra-emu/citra/pull/3504), [there](https://github.com/citra-emu/citra/pull/3666),
|
||||
and [that](https://github.com/citra-emu/citra/pull/3711)). The old way to upload the data (both vertex
|
||||
and constants) was a simple `glBufferData` call. Keep in mind, however, that the GPU has a huge execution
|
||||
latency, so you can't just copy the new content over the existing buffer. The driver has to choose
|
||||
between different ways to deal with this issue, with different drawbacks:
|
||||
|
||||
1. Wait for the GPU to finish and copy to the destination buffer. Usually this method is the fastest
|
||||
for big uploads, fine on common gaming, but terrible for emulators.
|
||||
2. Allocate a new buffer and tell the GPU which new buffer shall be used now. You also need to care
|
||||
about freeing the old buffer once it isn't in use any more. This tends to have a huge CPU overhead and
|
||||
isn't available on partial buffer updates such as lighting LUTs.
|
||||
3. Copy the data to an internal staging buffer and ask the GPU to copy it again to the destination
|
||||
when it is ready. This uses twice the memory bandwidth, and switching between rendering and copying also
|
||||
takes a while for the GPU. This proves to be a significant bottleneck if done for every single draw call.
|
||||
|
||||
In the end, all of these are bad in terms of performance. It is a simple upload call, but it either
|
||||
requires many copies and context switches, or the GPU is stalled (_More on that in [here](https://de.slideshare.net/CassEveritt/approaching-zero-driver-overhead)_). Instead, Citra
|
||||
allocates a big staging buffer, copies the data to the current position within the buffer,
|
||||
and tells the GPU to directly access the data from there. The driver has no scope of interpreting what
|
||||
we ask it to do.
|
||||
|
||||
_This has a downside as well_. The GPU now accesses the main memory over PCIe. So if we're going to
|
||||
reuse the same data in the next frame, it has to go through the PCIe bottleneck again. But, we never
|
||||
use the same data again and hence gain a big performance boost.
|
||||
|
||||
[wwylele](https://github.com/wwylele) tweaked the configuration UI and renamed some parts of it.
|
||||
However, this caused some confusion about the configuration window and GPU features.
|
||||
|
||||
### What's changed in the UI?
|
||||
|
||||
With the initial release of GLvtx, we added support for running shaders on the host GPU. So, we had
|
||||
a dropdown menu called **Shader Emulation** to select either CPU or GPU, to run the shaders. The
|
||||
option has now been renamed as **Enable Hardware Shader**. When enabled, it makes use of the host
|
||||
GPU, and when disabled, it uses the CPU alone.
|
||||
|
||||
Due to many of the users having older hardware, we introduced an option called **Accurate Hardware
|
||||
Shader**. It was later renamed to **Accurate Multiplication**, because technically that's what it was
|
||||
doing. ***When enabled it would render games with more accuracy at the cost of slower performance***.
|
||||
Same goes for **Accurate Geometry Shader**. Earlier this was configurable via the INI file, but now
|
||||
it can be configured in the UI.
|
||||
|
||||
|
||||
{{< sidebyside "image" "/images/entry/citra-progress-report-2018-q1/"
|
||||
"renderer-settings.png=Old Graphics Tab"
|
||||
"renderer-settings-new.png=New Graphics Tab" >}}
|
||||
|
||||
During it's time in Canary, a lot of testing was done by our contributors. They tested many games,
|
||||
under varied hardware conditions and submitted valuable telemetry data, crash logs, etc., which helped
|
||||
us in fixing issues with the hardware shader support.
|
||||
|
||||
**Note**:
|
||||
Unfortunately, due to driver issues with AMD GPUs and inadequate OpenGL support on macOS, the hardware
|
||||
shader might not perform better than the software renderer under these conditions. However, worry not,
|
||||
as research is being done into possible fixes that might come around sooner than you think.
|
||||
|
||||
Read more about hardware renderer improvements in detail [here](https://citra-emu.org/entry/improvements-to-hardware-renderer/).
|
||||
|
||||
## Continuous Integration (CI) Improvements ([here](https://github.com/citra-emu/citra/pull/3647), [there](https://github.com/citra-emu/citra/pull/3649), [this](https://github.com/citra-emu/citra/pull/3706), and [that](https://github.com/citra-emu/citra/pull/3744)) by [liushuyu](https://github.com/liushuyu)
|
||||
|
||||
One of the more time and resource consuming parts of the project were our build generating environments.
|
||||
We use Travis and Appveyor to release fully functional builds for download. However, the time it took
|
||||
for the builds to be created was too long and if it was stopped abruptly, it took even more time to
|
||||
create the builds again. Thanks to [liushuyu](https://github.com/liushuyu)'s contributions, we were
|
||||
able to optimize this whole process and make it very efficient to build and release latest changes to
|
||||
our site.
|
||||
|
||||
## Logging System Rewrite ([here](https://github.com/citra-emu/citra/pull/3449), [there](https://github.com/citra-emu/citra/pull/3533) and [that](https://github.com/citra-emu/citra/pull/3568)) by [jroweboy](https://github.com/jroweboy) and [daniellimws](https://github.com/daniellimws)
|
||||
|
||||
Our old logging system had several drawbacks and was due to be updated. So, a newer and efficient
|
||||
logging system based on fmtlib was designed and implemented by [jroweboy](https://github.com/jroweboy)
|
||||
and [daniellimws](https://github.com/daniellimws). This gets rid of the ugly console window and made
|
||||
many under the hood improvements to the logging system. This will make identifying and fixing issues
|
||||
a whole lot faster. After the implemetation was done, migrating our codebase to the new system was a
|
||||
huge endeavour shared by [daniellimws](https://github.com/daniellimws), and many others.
|
||||
|
||||
## [citra-qt: Camera Support](https://github.com/citra-emu/citra/pull/3566) by [zhaowenlan1779](https://github.com/zhaowenlan1779)
|
||||
|
||||
One of the highly requested features of Citra has been the support for using the system camera to
|
||||
scan QR codes and other kinds of images. [zhaowenlan1779](https://github.com/zhaowenlan1779) took it
|
||||
upon himself to provide Citra with this feature. By making use of the available Qt libraries, he worked
|
||||
on the implementation for weeks and was finally able to finish the feature. Citra now boasts the ability
|
||||
to directly scan images and use the system camera in a manner similar to the 3DS camera.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q1/camera.jpg"
|
||||
title="System Camera Support" >}}
|
||||
|
||||
## [citra-qt: Translations](https://github.com/citra-emu/citra/pull/3297) by [wwylele](https://github.com/wwylele) and [The Citra Community](https://community.citra-emu.org)
|
||||
|
||||
For a long while now, Citra’s UI had been in English and has had absolutely no support for other languages. [wwylele](https://github.com/wwylele) discussed this at length with other contributors and finally
|
||||
brought UI translations to Citra. Citra can now be used in many other languages. Note that these
|
||||
translations are maintained by our own community members and the translations are hosted on
|
||||
[Transifex](https://www.transifex.com/citra/citra/). Now, you too can submit a translation for your
|
||||
language (if it doesn’t exist already), or review existing translations to make them accurate.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q1/translation.jpeg"
|
||||
title="Citra - Now available in your language" >}}
|
||||
|
||||
## [Sending Test Cases via Telemetry](https://github.com/citra-emu/citra/pull/3325) by [BreadFish64](https://github.com/BreadFish64)
|
||||
|
||||
Over the years, Citra has improved by leaps and bounds. However, there has always been a lack of consistent
|
||||
information on game compatibility. We introduced the [game compatibility list](https://citra-emu.org/game/)
|
||||
to fix that. Having a list was helpful, but maintaining it was proving to be a tedious task. After a
|
||||
lot of brainstorming, [BreadFish64](https://github.com/BreadFish64) added the option in the UI to send
|
||||
test cases via telemetry. These results are submitted by the users themselves, and are in turn used to
|
||||
update the game compatibility list.
|
||||
|
||||
### Steps to submit test cases via Telemetry
|
||||
{{< sidebyside "image" "/images/entry/citra-progress-report-2018-q1/"
|
||||
"compat-1.png=Step 1"
|
||||
"compat-2.png=Step 2" >}}
|
||||
{{< sidebyside "image" "/images/entry/citra-progress-report-2018-q1/"
|
||||
"compat-3.png=Step 3"
|
||||
"compat-4.png=Step 4" >}}
|
||||
**Note**: To be able to report compatibility, you have to first login to the Citra Web Service, using
|
||||
your Username and Token.
|
||||
(See Emulation -> Configure -> Web)
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q1/web-verify.png"
|
||||
title="Citra Web Service" >}}
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
Various other contributions to the external dependencies have been made by [Lioncash](https://github.com/lioncash), [MerryMage](https://github.com/MerryMage), and many others. Several services were converted to the new
|
||||
service framework ([here](https://github.com/citra-emu/citra/issues/2531)). Many minor bug fixes and
|
||||
under-the-hood feature improvements were done by our [contributors](https://github.com/citra-emu/citra/graphs/contributors?from=2018-01-01&to=2018-05-19&type=c).
|
||||
We believe ***even the smallest contribution is valuable*** and without these [contributors](https://github.com/citra-emu/citra/graphs/contributors?from=2018-01-01&to=2018-05-19&type=c),
|
||||
these new features wouldn’t have been possible.
|
||||
|
||||
<h3 align="center">
|
||||
<b><a href="https://github.com/citra-emu/citra/">Contributions are always welcome !</a></b>
|
||||
</h3>
|
|
@ -0,0 +1,303 @@
|
|||
+++
|
||||
date = "2018-09-20T22:00:00+05:30"
|
||||
title = "Citra Progress Report - 2018 Q2"
|
||||
tags = [ "progress-report" ]
|
||||
author = "anodium"
|
||||
coauthor = "CaptV0rt3x"
|
||||
forum = 49673
|
||||
+++
|
||||
|
||||
Hello everyone to the summer (or winter, for those on the southern half of this
|
||||
Earth) edition of Citra's progress reports. Although not very many large changes
|
||||
have been made, many fixes have focused on accuracy improvements and implementing
|
||||
some of the sorely needed user experience features.
|
||||
|
||||
Before we go further into this, our [Patreon](https://www.patreon.com/citraemu/posts)
|
||||
poll results are out.
|
||||
We asked our patrons, which feature they would like to see us work on next and
|
||||
they delivered. Here are the results and as you will see, some of these have
|
||||
been considered and already implemented.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/patreon.png"
|
||||
title="Patreon Poll Results" >}}
|
||||
|
||||
To get access to such exclusives in the future and to support this project,
|
||||
consider becoming a patron. Now, enough appetizing, have your entrée:
|
||||
|
||||
## [Add pause, speed limit hotkeys](https://github.com/citra-emu/citra/pull/3594) by [valentinvanelslande](https://github.com/valentinvanelslande)
|
||||
|
||||
Let's start with a simple but sweet one — you can now assign hotkeys to
|
||||
pausing, unpausing, and toggling speed limiting. By default, you can pause with
|
||||
<kbd>F4</kbd> and toggle speed limiting with <kbd><kbd>Ctrl</kbd>+<kbd>Z</kbd></kbd>.
|
||||
But, of course, you can bind these actions to other keys in Citra's `qt-config.ini`.
|
||||
The property for pausing is `Shortcuts\Main%20Window\Continue\Pause\KeySeq` and
|
||||
for speed toggling it is `Shortcuts\Main%20Window\Toggle%20Speed%20Limit\KeySeq`.
|
||||
|
||||
## [Add support for multiple game directories](https://github.com/citra-emu/citra/pull/3617) by [BreadFish64](https://github.com/BreadFish64)
|
||||
|
||||
You can now configure Citra to search multiple directories for games and apps!
|
||||
This allow you to keep titles across different folders, and if you have any
|
||||
launchable titles installed into Citra's virtual SD card or NAND, they'll also
|
||||
show up in their own section so you can boot them from the game list.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/multiple_gamedirs.png"
|
||||
title="Multiple Game Directories" >}}
|
||||
|
||||
## [Add support for stereoscopic 3D](https://github.com/citra-emu/citra/pull/3632) by [N00byKing](https://github.com/N00byKing)
|
||||
|
||||
If you are one of the lucky few with a 3D TV or monitor attached to your
|
||||
computer, stereoscopic 3D support has just been added to Citra! You can enable
|
||||
it by heading to <kbd><samp>Emulation</samp> → <samp>Configure...</samp> → <samp>Graphics</samp> → <samp>Layout</samp></kbd>,
|
||||
ticking the <samp>Enable Stereoscopic 3D</samp> checkbox, and changing the
|
||||
screen layout to <samp>Side by Side</samp>.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/3d-sxs.png"
|
||||
title="Although you can't see this in 3D, try crossing your eyes or using a mirror!" >}}
|
||||
|
||||
## [Software Keyboard Implementation](https://github.com/citra-emu/citra/pull/3850) by [zhaowenlan1779](https://github.com/zhaowenlan1779) and [jroweboy](https://github.com/jroweboy)
|
||||
|
||||
For the longest time, many games were unplayable or needed workarounds on Citra
|
||||
due to them needing the software keyboard applet. The reason being that whenever
|
||||
they would try to open it, Citra didn't implement it, and so would simply tell
|
||||
the game that the user entered "Citra" and tapped OK, without actually prompting.
|
||||
But now, thanks to zhaowenlan1779 and jroweboy, it now has fully functional
|
||||
software keyboard emulation!
|
||||
|
||||
Whenever a game requests it, Citra will pause the game and pull up a text box that
|
||||
you can fill in like any other prompt.
|
||||
|
||||
{{< gifv src="/images/entry/citra-progress-report-2018-q2/swkbd.mp4"
|
||||
title="Now you can change your name to anything!" >}}
|
||||
|
||||
## Open Source System Archives ([#3977](https://github.com/citra-emu/citra/pull/3977), [#3881](https://github.com/citra-emu/citra/pull/3881)) by [B3n30](https://github.com/B3n30)
|
||||
|
||||
Many Nintendo 3DS games require the use of system archives, which contain things
|
||||
like fonts, a bad word list, and assets for Miis. Because these are copyrighted,
|
||||
Citra could not include them, and users had to dump a copy from their consoles,
|
||||
which was a generally tedious and error-prone process.
|
||||
|
||||
Now, [B3n30](https://github.com/B3n30) has created open source alternative fonts
|
||||
and a bad word list that can be used in games instead of the official archives.
|
||||
And, because these are open source, they are now included with Citra. If a game
|
||||
requires either archive, and you haven't dumped them yet, it'll automatically give
|
||||
the game the alternative archives. This is a step forward to Citra becoming
|
||||
a full-fledged HLE 3DS emulator.
|
||||
|
||||
## [Implement shadow map](https://github.com/citra-emu/citra/pull/3778) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
Shadow mapping is a way to quickly apply shadows to 3D scenes. It first renders
|
||||
the scene without any lighting, texture, or colour information, with a virtual
|
||||
camera from where the light source begins. Then, from that rendering the depth
|
||||
map is extracted. That is then applied as a texture to the darkened scene, making
|
||||
areas of it directly visible from the light source appear more brightly lit.
|
||||
|
||||
The PICA200 (the GPU inside the 3DS) and OpenGL both implement this in different
|
||||
ways, particularly in two important areas:
|
||||
|
||||
* The first is that PICA200 supports a variant called "soft shadows", where the
|
||||
depth map is blurred before being applied to the scene. This results in shadows
|
||||
that seem less jagged and sharp, making the light source feel more diffuse and
|
||||
evenly spread out throughout the scene. OpenGL doesn't support this at all.
|
||||
|
||||
* The second is that the PICA200 stores depth maps intended for shadow mapping as
|
||||
plain textures in the RGBA8 format. A lot of games exploit this in order to quickly
|
||||
convert other types of textures from an internal format to RGBA8. But, OpenGL
|
||||
stores these maps in a format internal to that graphics card, like any other map.
|
||||
(RGBA8 or 8bit RGBA is a texture format, which is the combination of an RGB
|
||||
(red green blue) color model with an extra 4th alpha channel.)
|
||||
|
||||
The first point isn't as significant, since the softness can be ignored on OpenGL,
|
||||
resulting in a very fast (but inaccurate) shadow mapping. Because games rarely
|
||||
use soft shadows, this can be ignored relatively safely.
|
||||
|
||||
The second point though, because games use it very often, it has to be implemented
|
||||
accurately. The naïve way would be to simply convert internal textures to RGBA8
|
||||
manually, but this would slow rendering down to a crawl. The smart way would be
|
||||
to try and trick the graphics card driver into performing a similar conversion,
|
||||
but such an attempt exposed a lot of issues, leading to instability.
|
||||
|
||||
After some very hard work by [wwylele](https://github.com/wwylele), both problems
|
||||
were solved with a single solution. OpenGL supports an extension called
|
||||
Image Load/Store, which allows shaders to read and write to any texture
|
||||
directly. Using this, he created a shader that could accurately implement both
|
||||
soft shadows, and convert the depth map from its internal format to RGBA8 very
|
||||
quickly.
|
||||
|
||||
{{< sidebyside "image" "/images/entry/citra-progress-report-2018-q2/"
|
||||
"shadowmap-before.png=Before Shadow Mapping"
|
||||
"shadowmap-after.png=After Shadow Mapping" >}}
|
||||
|
||||
Unfortunately, because Image Load/Store is an optional extension, not every
|
||||
OpenGL 3.3 graphics card will support it. In these cases, Citra will simply ignore
|
||||
shadow maps, making the rendering inaccurate but usable. Image Load/Store became
|
||||
a mandatory part of OpenGL in version 4.2, so every graphics card that complies
|
||||
with OpenGL 4.2 is guaranteed to work correctly.
|
||||
**Citra only requires a minimum
|
||||
compliance to OpenGL 3.3, but OpenGL 4.2 compliance may lead to more accurate
|
||||
rendering.**
|
||||
|
||||
## [Implement cubeb audio backend](https://github.com/citra-emu/citra/pull/3776) by [darkf](https://github.com/darkf)
|
||||
|
||||
[`cubeb`](https://github.com/kinetiknz/cubeb/) is an audio library (developed by
|
||||
the Mozilla Foundation) that's cross-platform, and most importantly ***fast***.
|
||||
Reports from [Dolphin's blog](https://dolphin-emu.org/blog/2017/06/03/dolphin-progress-report-may-2017/#50-3937-add-cubeb-audio-backend-by-ligfx)
|
||||
showed that it ran at a *third* of the latency of their OpenAL backend. And now,
|
||||
thanks to the work done by [darkf](https://github.com/darkf) and some fixes
|
||||
from [MerryMage](https://github.com/MerryMage), Citra can now benefit from that
|
||||
same low latency audio that Dolphin and Mozilla Firefox have. This will lead to
|
||||
significantly less distortion and stuttering in your games. Just remember to
|
||||
enable it in the configuration menu by setting `Output Engine` as `cubeb`.
|
||||
|
||||
## [Volume Slider](https://github.com/citra-emu/citra/pull/3831) by [Fearlesstobi](https://github.com/fearlesstobi)
|
||||
|
||||
You can now configure the volume level of Citra directly from the configuration
|
||||
window. This allows you to set an individual volume level for Citra without
|
||||
having to manually set it in your operating system settings.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/volume-slider.png"
|
||||
title="Volume Slider" >}}
|
||||
|
||||
## [Discord Rich Presence](https://github.com/citra-emu/citra/pull/3883) by [CaptV0rt3x](https://github.com/CaptV0rt3x)
|
||||
|
||||
Rich Presence allows you to leverage the totally boring "Now Playing" section
|
||||
in a Discord user's profile. This feature lets users show off when they are
|
||||
playing their favorite games on Citra. This has been a common feature request
|
||||
from many users, and since many other emulators have already implemented this,
|
||||
it made sense to implement it here as well.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/rpc.png"
|
||||
title="Discord Rich Presence" >}}
|
||||
|
||||
Discord Rich Presence works by creating a local connection with Citra and your
|
||||
Discord App. It ***does not*** connect to (or) send any data to Discord servers.
|
||||
This option is user configurable, so you can choose to show or not to show rich
|
||||
presence in your discord status. Just head out to <kbd><samp>Emulation</samp>
|
||||
→ <samp>Configure...</samp> → <samp>Web</samp> → <samp>Discord
|
||||
Presence</samp></kbd> and check / uncheck "Show current game in your Discord
|
||||
status".
|
||||
|
||||
## [Set Default values for settings](https://github.com/citra-emu/citra/pull/3924) by [zhaowenlan1779](https://github.com/zhaowenlan1779)
|
||||
|
||||
The majority of support requests we get are mostly due to users accidentally
|
||||
enabling or disabling some settings. But now with this feature, we have
|
||||
default values for all our settings. This ensures that in case of any new
|
||||
settings changes, majority of the users (who haven't customized those settings)
|
||||
will now have the new default value automatically.
|
||||
|
||||
## [Add support for encrypted games](https://github.com/citra-emu/citra/pull/4020) by [wwylele](https://github.com/wwylele)
|
||||
|
||||
You can now directly use your encrypted game dumps in Citra, without having to
|
||||
decrypt them. This requires that the user provide their keys via a text file
|
||||
in `sysdata/aes_keys.txt`.
|
||||
|
||||
Currently all known encryption methods are implemented except for the Seed
|
||||
crypto. Seed crypto is used in newer eshop games, which essentially uses an
|
||||
additional title-unique key that is stored outside of the ROM.
|
||||
|
||||
## [Scripting support](https://github.com/citra-emu/citra/pull/4016) by [EverOddish](https://github.com/EverOddish)
|
||||
|
||||
Scripting is an extremely useful feature which allows us to do things like
|
||||
debugging emulator internals, reverse engineering 3DS game internals,
|
||||
Tool-Assisted-Speedrunning (TAS), and the ability to manipulate memory in
|
||||
games. A cheat-like interface could be implemented through this (though, not
|
||||
specifically Gameshark / AR codes).
|
||||
|
||||
Users can make their own scripts or use publicly available scripts to gain
|
||||
power over things like game screen display, inputs, and memory. Scripts can
|
||||
also be used to read or modify the internal game state. EverOddish wrote some
|
||||
scripts that can read internal stats of the Pokémon and automatically
|
||||
update image files for your current party. This feature is very useful for
|
||||
streamers who might want to display game information on their streams.
|
||||
|
||||
## Movie - game input recording and playback ([#2882](https://github.com/citra-emu/citra/pull/2882), [#3922](https://github.com/citra-emu/citra/pull/3922)) by [danzel](https://github.com/danzel) and [zhaowenlan1779](https://github.com/zhaowenlan1779)
|
||||
|
||||
This feature, not to be confused with video/audio recording, implements a way
|
||||
to record game inputs and play them back. Every time the hardware reads an
|
||||
input device (buttons, touch screen, accelerometer, gyroscope, c-stick) the
|
||||
emulator copies (when recording) or replaces (when playing) the values. Once
|
||||
playback has finished, we release control of inputs so that the user can take
|
||||
control.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/movie.png"
|
||||
title="UI options to record" >}}
|
||||
|
||||
For this, danzel heavily took inspiration from dolphin's system and zhaowenlan1779
|
||||
wrote the UI for this feature. This method results in `.ctm` (Citra TAS movie)
|
||||
files which are playble in Citra. To play a game's `.ctm` file you would need
|
||||
to have the game and also manually set Citra's system time to the same starting
|
||||
value as in the `.ctm`. This feature makes debugging bugs in games much easier,
|
||||
as it doesn't require us to go through the whole process again.
|
||||
|
||||
## [Add system time configuration](https://github.com/citra-emu/citra/pull/4043) by [B3N30](https://github.com/b3n30)
|
||||
|
||||
Whenever a game requested time information, Citra always used your PC's system
|
||||
time. This method had a couple of issues - for example, if you were playing a game
|
||||
at 200% speed for 2 hours. As its running at twice the max speed, playing for
|
||||
2 hours in real-time should reflect 4 hours simulated time. But, due to Citra
|
||||
sending your PC's time to games, it wasn't happening.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/system-clock.png"
|
||||
title="System Time setting (edited to show both options)" >}}
|
||||
|
||||
Also, players might want to set Citra's time to a specific value to ensure
|
||||
consistency with TAS or with RNG(random number generator) or for getting
|
||||
time specific game events. Earlier you had to modify your PC's system time
|
||||
to achieve this but thanks to B3N30, you can now just set it in Citra's
|
||||
configuration window.
|
||||
|
||||
## [Joystick Hot-plugging](https://github.com/citra-emu/citra/pull/4141) by [B3N30](https://github.com/b3n30)
|
||||
|
||||
For a long time, Citra didn't support controller hot plugging. This meant that
|
||||
if by chance your controller disconnected Citra would fail to detect it after
|
||||
re-connection, unless you restarted the emulator. This caused a lot of
|
||||
frustration among users who preferred playing with controllers.
|
||||
|
||||
Hot plugging (also called hot swapping) is the ability to add and remove
|
||||
devices to a computer system while the computer is running and have the
|
||||
operating system automatically recognize the change.
|
||||
|
||||
Thanks to the efforts of B3N30 and [jroweboy](https://github.com/jroweboy)
|
||||
(who researched SDL controller configuration), Citra now doesn't fail to detect
|
||||
your controllers in case of a disconnection. However, due to heavy rework of
|
||||
the existing input configuration code, this requires users to reconfigure their
|
||||
controllers after updating Citra.
|
||||
|
||||
## UDP client to provide motion & touch controls ([#4049](https://github.com/citra-emu/citra/pull/4049), [#4059](https://github.com/citra-emu/citra/pull/4059)) by [jroweboy](https://github.com/jroweboy) and [zhaowenlan1779](https://github.com/zhaowenlan1779)
|
||||
|
||||
Citra's previous motion controls were a bit uncomfortable to use. You had to
|
||||
use your mouse's right-click and drag to tilt the screen, but it was often
|
||||
hard to figure out where to move the cursor to get the kind of tilt we want.
|
||||
|
||||
Using a real device for motion controls is simply much more intuitive and will
|
||||
be an all around better experience for users. As such, jroweboy set out to
|
||||
implement cemuhook motion/touch protocol which adds the ability for users to
|
||||
connect several different devices to citra to send direct motion and touch
|
||||
data to citra.
|
||||
|
||||
{{< figure src="/images/entry/citra-progress-report-2018-q2/cemuhookudp.png"
|
||||
title="Motion/Touch Configuration Window" >}}
|
||||
|
||||
[Cemuhook](https://cemuhook.sshnuke.net/) is a very popular plugin developed by [rajkosto](https://github.com/rajkosto)
|
||||
for Cemu - the Wii U emulator. This protocol was chosen simply because of the
|
||||
fact that there aren't many alternatives and this already has good device
|
||||
support. Moreover, as it uses UDP, it works on just about anything with a
|
||||
network stack and allows the server to even be a remote network device (useful
|
||||
for Android motion support). zhaowenlan1779 wrote the UI for this feature,
|
||||
to make it easily accessible and configurable by all users.
|
||||
|
||||
## Et. al.
|
||||
|
||||
Apart from the above mentioned ones, we have also had a lot of minor optimizations
|
||||
and bug fixes ported from yuzu. We've made changes to our authentication system
|
||||
to use JWT (JSON web tokens), added a background color selector, made GDB stub
|
||||
improvements, and many more.
|
||||
|
||||
Thank you to [everyone](https://github.com/citra-emu/citra/graphs/contributors?from=2018-05-20&to=2018-08-31&type=c)
|
||||
for pouring your blood and sweat into this project. Citra needs contributors
|
||||
like you to stay alive and become the best it can be.
|
||||
|
||||
|
||||
<h4 style="text-align:center;">
|
||||
<b>Please consider supporting us on [Patreon](https://www.patreon.com/citraemu)!<br>
|
||||
If you would like to contribute to this project, checkout our [GitHub](https://github.com/citra-emu/citra)!</b>
|
||||
</h4>
|
|
@ -6,12 +6,24 @@ author = "saphiresurf"
|
|||
forum = 1943
|
||||
+++
|
||||
|
||||
As game compatibility has broadened and the popularity of Citra has risen there's always been a lack of consistent information on what could be played in Citra and what couldn't. Often times the best way to find out if a game was working properly in Citra was to jump in and test it for yourself, but if any issues were encountered you'd be left scouring through forums sifting through potentially out of date information for answers.
|
||||
As game compatibility has broadened and the popularity of Citra has risen there's always been a lack of consistent
|
||||
information on what could be played in Citra and what couldn't. Often times the best way to find out if a game was
|
||||
working properly in Citra was to jump in and test it for yourself, but if any issues were encountered you'd be left
|
||||
scouring through forums sifting through potentially out of date information for answers.
|
||||
|
||||
In order to address this issue [Flame Sage](https://community.citra-emu.org/u/flamesage/summary), [Flamboyant Ham](https://community.citra-emu.org/u/flamboyant_ham/summary), [leo121](https://community.citra-emu.org/u/leo121/summary), [anodium](https://community.citra-emu.org/u/anodium/summary), and [TheKoopaKingdom](https://community.citra-emu.org/u/thekoopakingdom/summary) have worked hard to create a new game compatibility wiki! As time goes on more and more titles from the 3DS library will be added to this list. As they're added in, each game will be given a compatibility rating based on how well and how smoothly they run in Citra. On each game's individual page there will be a summary of the game itself, how it runs on Citra, as well as any problems that arise when running the game.
|
||||
In order to address this issue [Flame Sage](https://community.citra-emu.org/u/flamesage/summary),
|
||||
[Flamboyant Ham](https://community.citra-emu.org/u/flamboyant_ham/summary),
|
||||
[leo121](https://community.citra-emu.org/u/leo121/summary),
|
||||
[anodium](https://community.citra-emu.org/u/anodium/summary), and
|
||||
[TheKoopaKingdom](https://community.citra-emu.org/u/thekoopakingdom/summary) have worked hard to create a new game
|
||||
compatibility wiki! As time goes on more and more titles from the 3DS library will be added to this list. As they're
|
||||
added in, each game will be given a compatibility rating based on how well and how smoothly they run in Citra. On each
|
||||
game's individual page there will be a summary of the game itself, how it runs on Citra, as well as any problems that
|
||||
arise when running the game.
|
||||
|
||||
We encourage community contributions to this list as well! If you'd like to add new entries to this list you can find out how to contribute [here](https://github.com/citra-emu/citra-games-wiki/blob/master/CONTRIBUTING.md).
|
||||
We encourage community contributions to this list as well! If you'd like to add new entries to this list you can find
|
||||
out how to contribute [here](https://github.com/citra-emu/citra-games-wiki/blob/master/CONTRIBUTING.md).
|
||||
|
||||
Thank you everyone for continuing on this journey with us!
|
||||
|
||||
[Check Out The Compatibility List Here] (https://citra-emu.org/game/)
|
||||
[Check Out The Compatibility List Here](https://citra-emu.org/game/)
|
||||
|
|
|
@ -6,39 +6,65 @@ author = "merrymage"
|
|||
forum = 38
|
||||
+++
|
||||
|
||||
*Special thanks must be given to fincs and the rest of the 3DS community for their work reverse-engineering the DSP firmware. Without that work, Citra would not be this far with audio emulation.*
|
||||
*Special thanks must be given to fincs and the rest of the 3DS community for their work reverse-engineering the DSP
|
||||
firmware. Without that work, Citra would not be this far with audio emulation.*
|
||||
|
||||
As of [May 19th, 2016](https://github.com/citra-emu/citra/commit/af258584d978f02d462743012491a273c61b067e), Citra now has preliminary High Level Emulation (HLE) audio support! This means that users playing on Citra no longer have to listen to the deafening sound of silence in many titles. To get to this point was a huge reverse-engineering effort done by multiple people, with much of the reverse-engineering and the final implementation for Citra coming from MerryMage. This undertaking has required many months of development but the end result brings sound to the masses.
|
||||
As of [May 19th, 2016](https://github.com/citra-emu/citra/commit/af258584d978f02d462743012491a273c61b067e), Citra now
|
||||
has preliminary High Level Emulation (HLE) audio support! This means that users playing on Citra no longer have to
|
||||
listen to the deafening sound of silence in many titles. To get to this point was a huge reverse-engineering effort
|
||||
done by multiple people, with much of the reverse-engineering and the final implementation for Citra coming from
|
||||
MerryMage. This undertaking has required many months of development but the end result brings sound to the masses.
|
||||
|
||||
{{< youtube 8LCUlyjvTJU >}}
|
||||
|
||||
## **Technical Details on how Audio Works for the 3DS**
|
||||
## Technical Details on how Audio Works for the 3DS
|
||||
|
||||
Audio processing and output is done by a specialised coprocessor. These kinds of coprocessors are called Digital Signal Processors (DSPs).
|
||||
Audio processing and output is done by a specialised coprocessor. These kinds of coprocessors are called Digital Signal
|
||||
Processors (DSPs).
|
||||
|
||||
Games that run on the 3DS need to communicate with the DSP in order to play audio. They do this by two ways: via the the <span style="font-family:'Courier New'">dsp::DSP</span> service and via a shared memory region. The <span style="font-family:'Courier New'">dsp::DSP</span> service provides service calls for initialization of the DSP hardware including firmware upload. The shared memory region is used for communication between the game on the CPU and the firmware on the DSP.
|
||||
Games that run on the 3DS need to communicate with the DSP in order to play audio. They do this by two ways: via the
|
||||
the `dsp::DSP` service and via a shared memory region. The `dsp::DSP` service provides service calls for initialization
|
||||
of the DSP hardware including firmware upload. The shared memory region is used for communication between the game on
|
||||
the CPU and the firmware on the DSP.
|
||||
|
||||
In order to emulate audio, Citra must emulate the <span style="font-family:'Courier New'">dsp::DSP</span> service and also understand the layout of the DSP shared memory region. One must understand what writing to various addresses in the shared memory region does. One must also understand what happens between data being fed to the DSP firmware and audio coming out of the speakers.
|
||||
In order to emulate audio, Citra must emulate the `dsp::DSP` service and also understand the layout of the DSP shared
|
||||
memory region. One must understand what writing to various addresses in the shared memory region does. One must also
|
||||
understand what happens between data being fed to the DSP firmware and audio coming out of the speakers.
|
||||
|
||||
## **Early Reverse Engineering**
|
||||
## Early Reverse Engineering
|
||||
|
||||
With this known MerryMage set out to trace reads and writes to shared memory that games did. She eventually ended up playing these back on hardware and figured out what the appropriate firmware responses were. This eventually lead to the early implementations of audio output that originally were shown in January by various users. Many other aspects, including ADPCM decoding, took a while to figure out. <br></br>
|
||||
With this known MerryMage set out to trace reads and writes to shared memory that games did. She eventually ended up
|
||||
playing these back on hardware and figured out what the appropriate firmware responses were. This eventually lead to
|
||||
the early implementations of audio output that originally were shown in January by various users. Many other aspects,
|
||||
including ADPCM decoding, took a while to figure out.
|
||||
|
||||
{{< youtube 1c_A7gpAZ8A >}}
|
||||
<br></br>
|
||||
|
||||
MerryMage had raw audio output working but she still didn’t understand how various parameters were applied to the audio by the firmware. It was at this point where she discovered that the firmware writes back what is output to the speakers into the shared memory region. This discovery made future work with audio effects much easier as bit perfect audio could be dumped as the 3DS produced it without any extra hardware. Having real hardware audio output on hand meant MerryMage could also apply signal processing techniques like system identification to figure out what internal processing the firmware does.
|
||||
MerryMage had raw audio output working but she still didn’t understand how various parameters were applied to the audio
|
||||
by the firmware. It was at this point where she discovered that the firmware writes back what is output to the speakers
|
||||
into the shared memory region. This discovery made future work with audio effects much easier as bit perfect audio
|
||||
could be dumped as the 3DS produced it without any extra hardware. Having real hardware audio output on hand meant
|
||||
MerryMage could also apply signal processing techniques like system identification to figure out what internal
|
||||
processing the firmware does.
|
||||
|
||||
With this newfound knowledge and this new set of tools MerryMage rapidly conquered what the firmware was doing.
|
||||
|
||||
## **Time Stretching**
|
||||
## Time Stretching
|
||||
|
||||
Emulation speed can vary a lot between games or even parts of games. To accomodate this, time streching was added as an audio enhancement. This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This is an effect completely separate from emulation and is only to alter and improve audio played back when the emulator is not going full speed.
|
||||
Emulation speed can vary a lot between games or even parts of games. To accomodate this, time streching was added as an
|
||||
audio enhancement. This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio
|
||||
stutter. This is an effect completely separate from emulation and is only to alter and improve audio played back when
|
||||
the emulator is not going full speed.
|
||||
|
||||
## **Future Plans for Audio**
|
||||
## Future Plans for Audio
|
||||
|
||||
Audio is still not complete! There are still a number of unimplemented features and accuracy improvements to have. Many of these features have been reverse engineered already but simply aren't implemented. This includes reverb, delay, and other minor audio effects. Some features require more reverse engineering work, such as looped buffers and surround sound.
|
||||
Audio is still not complete! There are still a number of unimplemented features and accuracy improvements to have. Many
|
||||
of these features have been reverse engineered already but simply aren't implemented. This includes reverb, delay, and
|
||||
other minor audio effects. Some features require more reverse engineering work, such as looped buffers and surround
|
||||
sound.
|
||||
|
||||
While the black-box reverse engineering approach has served well so far, further improvements in accuracy can more easily be made by decompiling the firmware and perhaps implementing Low Level Emulation (LLE) audio. This comes with its own set of challenges especially as the DSP architecture is not well known and there is little documentation on it.
|
||||
While the black-box reverse engineering approach has served well so far, further improvements in accuracy can more
|
||||
easily be made by decompiling the firmware and perhaps implementing Low Level Emulation (LLE) audio. This comes with
|
||||
its own set of challenges especially as the DSP architecture is not well known and there is little documentation on it.
|
||||
|
||||
Until then, we at Citra hope that everyone enjoys this initial HLE audio implementation!
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
+++
|
||||
date = "2018-03-10T17:00:00-04:00"
|
||||
title = "Hardware Renderer Updates"
|
||||
tags = [ "feature-update" ]
|
||||
author = "jroweboy"
|
||||
banner = "hardware-shaders.png"
|
||||
forum = 11831
|
||||
+++
|
||||
|
||||
## Cut to the chase, how fast is this?
|
||||
|
||||
{{<
|
||||
sidebyside "gifv" "/images/entry/improvements-to-hardware-renderer/"
|
||||
"before.mp4=Before"
|
||||
"after.mp4=After"
|
||||
>}}
|
||||
|
||||
<h4 style="text-align: center;">Realtime performance comparison with framelimit off</h4>
|
||||
<!--more-->
|
||||
Very fast. Test results across various computers show that it **averages out to be a 2x speed boost.**
|
||||
With the new update, Citra will use much more of your GPU, removing some of the dependence on a CPU with high single-core performance.
|
||||
As always, the actual difference will vary by game and by your specific hardware configuration!
|
||||
In celebration of this massive improvement, we wanted to share some of the successes and struggles we've had over the years with the hardware renderer.
|
||||
|
||||
## Brief History of Citra's Rendering Backends
|
||||
|
||||
Back in early 2015, Citra was still a young emulator, and had just barely started displaying graphics for the first time.
|
||||
In a momentous occasion, Citra displayed 3D graphics from a commercial game, Legend of Zelda: Ocarina of Time 3D
|
||||
|
||||
{{< figure type="youtube" id="sYukdJam6gk" title="It took a year from when citra started to get to this point" >}}
|
||||
|
||||
This engineering feat was thanks to the hard work of many contributors in both the emulator scene and the 3ds hacking scene, who worked tirelessly to reverse engineer the 3DS GPU, a chip called the PICA200.
|
||||
But not even a few months later, Citra was able to play the game at full speed!
|
||||
|
||||
{{< figure type="youtube" id="Hj8sPsB5qXQ" title="Good thing that shield flashing bug still isn't around" >}}
|
||||
|
||||
Why is there such a major difference in speed from the first and the second video?
|
||||
The speed difference boils down to how the 3DS GPU is being emulated.
|
||||
The first video is showing off the software renderer, which emulates the PICA200 by using your computer's CPU.
|
||||
On the other hand, the second video is using the OpenGL hardware renderer, which emulates the PICA200 by using your computer's GPU.
|
||||
From those videos, using your GPU to emulate the 3DS GPU is the clear winner when it comes to speed!
|
||||
However, it's not all sunshine and daisies; there's always tradeoffs in software development.
|
||||
|
||||
## Challenges in the Hardware Renderer
|
||||
|
||||
Earlier it was stated that the OpenGL hardware renderer was emulating the PICA200 by using the GPU instead of the CPU, and ... that's only partially true.
|
||||
As it stands, only a portion of the PICA200 emulation is running on the GPU; most of it is running on the CPU!
|
||||
To understand why, we need to dive a little deeper into the difference between CPUs and modern GPUs.
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/gpu_pipeline_before.png"
|
||||
title="The green shaded portions are what Citra emulates using the GPU. For a hardware renderer, Citra isn't using the GPU much!"
|
||||
>}}
|
||||
|
||||
As a general rule of thumb, CPUs are fast at computing general tasks, while GPUs are *blazing fast* at computing very specific tasks.
|
||||
Whenever the tasks the PICA200 can perform matches up with tasks you can do on a GPU using OpenGL, everything is fast and everyone is happy!
|
||||
That said, we tend to run into edge cases that the PICA200 supports, but frankly, OpenGL is not well suited to support.
|
||||
This leads to cases where sometimes we just have to [live with minor inaccuracies as a tradeoff for speed.](https://github.com/citra-emu/citra/pull/2697)
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/outline_bug.png" title="The infamous Pokémon outlines bug was one such example of something that OpenGL just doesn't handle well" >}}
|
||||
|
||||
OpenGL is also great for emulator developers because it's a cross-platform standard for graphics, with support for all major desktop platforms.
|
||||
But because OpenGL is just a specification, every vendor is left up to their own to make their drivers support the specification for every individual platform.
|
||||
This means performance and features can vary widely between operating systems, graphics driver, and the physical graphics card.
|
||||
As you might have guessed, this leads to some [OS specific bugs that are very hard to track down](https://github.com/citra-emu/citra/issues/2416).
|
||||
In the linked issue, only on Mac OSX, Citra would leak memory from the hardware renderer.
|
||||
We traced it back to how textures were juggled between the 3DS memory and the host GPU, but we don't have many developers that use Mac, so we never did find the root cause.
|
||||
For a little bit of good news, **this is fixed in the latest nightly**, but only because the entire texture handling code was rewritten!
|
||||
|
||||
## Moving Forward with the Hardware Renderer: Cleaning up Texture Forwarding
|
||||
|
||||
Despite the issues mentioned above, OpenGL has been a fair choice for a hardware renderer, and [phantom](https://github.com/phanto-m/) has been hard at work improving the renderer.
|
||||
Their first major contribution was a massive, [complete rewrite](https://github.com/citra-emu/citra/pull/3281) of the [texture forwarding support](https://citra-emu.org/entry/texture-forwarding-brings-hd-output-to-citra/) that was added back in 2016.
|
||||
The new texture forwarding code increases the speed of many games, and fixes upscaled rendering in some other games as well.
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/metroid_before.png"
|
||||
title="Metroid: Samus Returns heavily used a PICA200 feature that had a comment `// TODO: implement this` in the hardware renderer" >}}
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/metroid_after.png"
|
||||
title="Writing that missing method fixed upscaling while making the game much faster" >}}
|
||||
|
||||
Whenever a texture is used in the hardware renderer, the hardware renderer will try to use a copy of the texture already in the GPU memory, but if that fails, it has to reload the texture from the emulated 3DS memory.
|
||||
This is called a texture upload, and it's slow for a good reason.
|
||||
The communication between CPU and GPU is optimized for large amounts of data transferred, but as a tradeoff, it's not very fast.
|
||||
This works great for PC games, where you know all the textures you want to upload ahead of time and can send them in one large batch, but ends up hurting performance for Citra since we can't know in advance when the emulated game will do something that requires a texture upload.
|
||||
|
||||
The texture forwarding rewrite increases the speed of many games by adding in new checks to avoid this costly synchronization of textures between emulated 3DS memory and the host GPU memory.
|
||||
Additionally, the new texture forwarding can avoid even more texture uploads by copying the data from any compatible locations.
|
||||
As an extension of this feature, [phantom](https://github.com/phanto-m/) went the extra mile and fixed Pokémon outlines as well!
|
||||
Pokémon games would draw the outline by reinterpreting the depth and stencil buffer as an RGBA texture, using the value for the red color to draw the outline.
|
||||
Sadly, OpenGL doesn't let you just reinterpret like that, meaning we needed to be more creative.
|
||||
[phantom](https://github.com/phanto-m/) worked around this limitation by copying the data into a [Pixel Buffer Object](https://www.khronos.org/opengl/wiki/Pixel_Buffer_Object), and running a shader to extract the data into a [Buffer Texture](https://www.khronos.org/opengl/wiki/Buffer_Texture) which they could use to draw into a new texture with the correct format.
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/outline_upscaled.png" title="The long standing issue is gone!" >}}
|
||||
|
||||
The texture forwarding rewrite has been battle tested in Citra Canary for the last 2 months, during which time we fixed over 20 reported issues.
|
||||
We are happy to announce that it's now merged into the master branch, so please enjoy the new feature in the latest nightly build!
|
||||
|
||||
## The Big News You've Been Waiting For
|
||||
|
||||
A few paragraphs ago, we mentioned that Citra's hardware renderer did most of the emulation on the CPU, and only some of it on the GPU.
|
||||
The big news today is Citra now does the **entire GPU emulation on the host GPU**.
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/gpu_pipeline_after.png" title="Just look at all that green for each pipeline stage!" >}}
|
||||
|
||||
With an unbelievable amount of effort, [phantom](https://github.com/phanto-m/) has done it again.
|
||||
Moving the rest of the PICA200 emulation to the GPU was always a sort of "white whale" for Citra.
|
||||
We knew it would make things fast, but the sheer amount of effort required to make this happen scared off all those who dared attempt it.
|
||||
But before we get into why this was so challenging, let's see some real performance numbers!
|
||||
|
||||
#### All testing was done with the following settings: 4x Internal Resolution, Accurate Hardware Shaders On, Framelimit Off
|
||||
|
||||
{{< figure size="large" src="/images/entry/improvements-to-hardware-renderer/gpu_vendor_graph.png" title="Dedicated GPUs saw the biggest improvement" >}}
|
||||
|
||||
{{< figure size="large" src="/images/entry/improvements-to-hardware-renderer/midend_gpu_graph.png" title="Mid-High end GPUs tend to be fast" >}}
|
||||
|
||||
{{< figure size="large" src="/images/entry/improvements-to-hardware-renderer/lowend_gpu_graph.png" title="Low-Mid end GPUs are just a bit fast" >}}
|
||||
|
||||
{{< figure size="large" src="/images/entry/improvements-to-hardware-renderer/pokemon_beforeafter_graph.png" title="According to telemetry data, Pokémon is the most played game on Citra" >}}
|
||||
|
||||
{{< figure size="large" src="/images/entry/improvements-to-hardware-renderer/mh_beforeafter_graph.png" title="But Monster Hunter is catching up in playtime" >}}
|
||||
|
||||
## Obstacles to Emulating the PICA200 on a GPU
|
||||
|
||||
### Making Functions Out of GOTOs
|
||||
|
||||
It's likely that the game developers for the 3DS didn't have to write PICA200 GPU assembly, but when emulating the PICA200, all Citra can work with is a commandlist and a stream of PICA200 opcodes.
|
||||
While the developers probably wrote in a high level shader language that supports functions, when the shaders are compiled, most of that goes away.
|
||||
The PICA200 supports barebones `CALL`, `IF`, and `LOOP` operations, but also supports an arbitrary `JMP` that can go to any address.
|
||||
Translating PICA200 shaders into GLSL (OpenGL Shader Language) means that you'll have to be prepared to rewrite every arbitrary `JMP` without using a `goto` as GLSL doesn't support them.
|
||||
|
||||
[phantom](https://github.com/phanto-m/) assumed the worst when they originally translated PICA200 shaders into GLSL and wrote a monstrous switch statement that would have a case for every jump target and act as a PICA200 shader interpreter.
|
||||
This worked, but proved to be slower than the software renderer!
|
||||
Now that [phantom](https://github.com/phanto-m/) knew it was possible, and they had some data about how the average PICA200 shader looked, they took to rewrite it with the goal to make it fast.
|
||||
While the shaders could theoretically be very unruly and hard to convert, almost all the shaders were well behaved, presumably because they are compiled from a higher level language.
|
||||
This time around, [phantom](https://github.com/phanto-m/) generated native GLSL functions wherever possible by analyzing the control flow of the instructions, and the results are much prettier and faster.
|
||||
Armed with the new knowledge, [phantom](https://github.com/phanto-m/) rewrote the conversion a third time, and optimized the generated shaders even further.
|
||||
What started off slower than the software renderer ended up being the massive performance boost we have today!
|
||||
|
||||
### Multiplication Shouldn't Be This Slow
|
||||
|
||||
When converting from PICA200 shaders into GLSL, there are a few PICA200 opcodes that should just match up without any issues.
|
||||
Addition, subtraction, and multiplication should ... wait. Where did this issue come from?
|
||||
|
||||
{{< sidebyside "image" "/images/entry/improvements-to-hardware-renderer/"
|
||||
"accurate_mul_on.png=On: I don't see any issue..."
|
||||
"accurate_mul_off.png=Off: Oh. Well maybe Eren looks better this way" >}}
|
||||
|
||||
It turns out that the PICA200 multiplication opcode has a few edge cases that don't impact a large majority of games, and leads to some hilarious results in others.
|
||||
On the PICA200, `infinity * 0 = 0` but in OpenGL `infinity * 0 = NaN` and this can't be configured.
|
||||
In the generated GLSL shaders, [phantom](https://github.com/phanto-m/) emulates this behavior by making a function call instead of a simple multiplication.
|
||||
|
||||
```glsl
|
||||
vec4 sanitize_mul(vec4 lhs, vec4 rhs) {
|
||||
vec4 product = lhs * rhs;
|
||||
return mix(product, mix(mix(vec4(0.0), product, isnan(rhs)), product, isnan(lhs)), isnan(product));
|
||||
}
|
||||
```
|
||||
|
||||
Alas, it's a performance penalty to use a function everywhere instead of regular multiplication.
|
||||
On weaker GPUs, we noticed the penalty is so severe, we actually made this configurable.
|
||||
The whole point of a hardware renderer is to be fast, so eating a penalty when only a small handful of games need this level of accuracy would be regrettable.
|
||||
You can turn off this feature in the settings by deselecting "Accurate Hardware Shader" and get a noticeable performance boost, but be aware that a few games will break in strange ways!
|
||||
|
||||
### Finding Bugs and Working Overtime
|
||||
|
||||
We were very excited to launch this feature when [phantom](https://github.com/phanto-m/) declared that it was ready; results from user testing were entirely positive, and the performance improvements were unbelievable, but one thing stood in the way.
|
||||
No one had yet tested to see if it worked on AMD GPUs.
|
||||
We called for our good friend [JMC47](https://dolphin-emu.org/blog/authors/JMC47/) to break out the AMD card he uses for testing Dolphin, and Citra crashed the driver! Oh no!
|
||||
|
||||
From [JMC47](https://dolphin-emu.org/blog/authors/JMC47/)'s time in Dolphin, he's made a few friends here and there, and he found someone willing to investigate.
|
||||
After a few gruelling weeks, [JonnyH](https://github.com/JonnyH) was able to narrow down what the problem is, and luckily it's not a bug in the AMD drivers.
|
||||
It turns out that it's a bug in the GL specification, or more precisely, the exact issue is ambiguous wording.
|
||||
[glDrawRangeElementsBaseVertex](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDrawRangeElementsBaseVertex.xhtml) states that the indices should be a pointer, but doesn't say whether the pointer should be to CPU memory or GPU memory.
|
||||
Citra passed a pointer to CPU memory without a second thought, as both Nvidia and Intel drivers seemed fine with it, but AMD drivers are strict.
|
||||
As a workaround, [phantom](https://github.com/phanto-m/) added support for streaming storage buffers, which allows Citra to work with the data on the CPU and sync it with the GPU when it's time to draw.
|
||||
|
||||
It's a challenge to support all of the many GPUs out there, and we've put in so much work to ensure that this new feature will run on as many hardware configurations as possible.
|
||||
But it's very likely that there will be some GPUs that do not fully support the new hardware renderer, and so we added another option in the Configuration to allow users to turn this feature off entirely.
|
||||
Simply changing the "Shader Emulation" from "GPU" to "CPU" will revert to using the same old CPU shaders that Citra was using before.
|
||||
|
||||
{{< figure src="/images/entry/improvements-to-hardware-renderer/renderer_settings.png" title="Check out the new Renderer settings in the Graphics tab" >}}
|
||||
|
||||
## What's next
|
||||
|
||||
While today marks a victory for fast emulation, we always have room for improvement.
|
||||
As explained earlier in the article, getting OpenGL to work consistently across all platforms and GPUs is surprisingly challenging, so be ready for bugs.
|
||||
This isn't the end for the hardware renderer, but a wonderful boost to one of Citra's more complicated features.
|
||||
There is always something more that can be done to make the hardware renderer even faster and more accurate (contributions welcome!), but in the meantime, we hope you enjoy playing even more games at full speed!
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
+++
|
||||
date = "2017-10-22T22:47:14-05:00"
|
||||
title = "Introducing Automatic Updates"
|
||||
tags = [ "feature-update" ]
|
||||
author = "thekoopakingdom"
|
||||
forum = 4428
|
||||
+++
|
||||
|
||||
Emulators grow quickly. Last month alone, there were [39 pull requests](https://github.com/citra-emu/citra/pulls?utf8=%E2%9C%93&q=is%3Amerged%20merged%3A2017-09-01..2017-09-30%20)
|
||||
merged to Citra. For this reason, it's important to be able to manage the many different
|
||||
versions of an emulator. Until now however, Citra has had no installer or updater
|
||||
for the [nightly builds](https://github.com/citra-emu/citra-nightly/releases). Although
|
||||
the now obsolete [Bleeding Edge builds](https://github.com/citra-emu/citra-bleeding-edge/releases)
|
||||
did have both of these things, it was limited to Windows, and the installer framework
|
||||
had some issues that restricted what we could do with it.
|
||||
|
||||
Thanks to the work by [j-selby](https://github.com/j-selby) and [jroweboy](https://github.com/jroweboy),
|
||||
we now have a new installer and updater for both the [Nightly builds](https://github.com/citra-emu/citra-nightly/releases)
|
||||
and the [Canary builds](https://github.com/citra-emu/citra-canary/releases)!
|
||||
|
||||
More info on the Canary version of Citra will be in the **September 2017 Progress
|
||||
Report**.
|
||||
|
||||
## Installer
|
||||
The [new installer](https://github.com/citra-emu/citra/pull/2966) is an application
|
||||
separate from Citra itself, that utilizes the [Qt Installer Framework](https://doc.qt.io/qtinstallerframework/index.html)
|
||||
(Also known as QtIFW.) to download the latest version of either Citra
|
||||
Nightly or Citra Canary from our website's repository and extract it to your system's
|
||||
program directory.
|
||||
|
||||
{{< figure src="/images/entry/introducing-automatic-updates/installer-options.png"
|
||||
title="CHOOSE YOUR WEAPON" alt="Installer options." >}}
|
||||
|
||||
Additionally, depending on which build(s) you chose, the installer
|
||||
will also create desktop icons for easy access. You can get the installer from the
|
||||
[downloads page](https://citra-emu.org/download/), which will try to automatically
|
||||
select the correct version for your OS.
|
||||
|
||||
## Updater
|
||||
In addition to installing, QtIFW also provides functionality for updating via the
|
||||
`maintenancetool` utility. For convenience, this is [integrated into the Qt frontend](https://github.com/citra-emu/citra/pull/2997)
|
||||
(The main GUI that you probably use.) in the form of scheduled automatic
|
||||
updates. You can optionally check for updates on startup, and/or check for updates
|
||||
on shutdown.
|
||||
|
||||
{{< figure src="/images/entry/introducing-automatic-updates/configuration.png"
|
||||
title="Note the two checkboxes in the updates section." alt="Configuration window." >}}
|
||||
|
||||
If an update is found at startup, you will be asked if you want to run the updater
|
||||
or not.
|
||||
|
||||
{{< figure src="/images/entry/introducing-automatic-updates/update-prompt.png"
|
||||
title="Gotta keep your Citrus fresh!" alt="Message box prompting for installation." >}}
|
||||
|
||||
If an update is found at shutdown, Citra will silently update without prompting,
|
||||
because at this point emulation has already been terminated.
|
||||
|
||||
You can also manually update your Citra installation at any time, by going to the
|
||||
`Help` menu, and then `Check for Updates`.
|
||||
|
||||
## Uninstallation & Install Modification
|
||||
QtIFW's `maintenancetool` can also be used to uninstall Citra, and install a different
|
||||
type of build. Like the updater, this is also integrated into the Qt frontend, and
|
||||
can be accessed by going to the `Help` menu, and then `Modify Citra Install`. Integrating
|
||||
with an already well-established framework like QtIFW allows us to streamline the
|
||||
task of installation maintenence.
|
|
@ -5,24 +5,31 @@ author = "thekoopakingdom"
|
|||
forum = 40
|
||||
+++
|
||||
|
||||
```DISCLAIMER: You do NOT need to follow this guide if you downloaded Citra for the first time after December 6th, 2016 OR if you have freshly installed Citra since using an older build.```
|
||||
**DISCLAIMER: You do NOT need to follow this guide if you downloaded Citra for the first time after December 6th, 2016
|
||||
OR if you have freshly installed Citra since using an older build.**
|
||||
|
||||
In new versions of Citra, the location of saves has changed, so this guide will show how to migrate your saves to the new location on Window (Linux and macOS Bleeding Edge builds are planned, we are currently busy working on bringing nightly builds back.).
|
||||
In new versions of Citra, the location of saves has changed, so this guide will show how to migrate your saves to the
|
||||
new location on Windows (Linux and macOS Bleeding Edge builds are planned, we are currently busy working on bringing
|
||||
nightly builds back.).
|
||||
|
||||
1. Press Windows + R, type ```explorer %localappdata%```, this should bring up a Windows Explorer window in a ```Local``` folder. Navigate to the ```citra``` folder.
|
||||
<br></br>
|
||||
1. Press Windows + R, type `explorer %localappdata%`, this should bring up a Windows Explorer window in a `Local`
|
||||
folder. Navigate to the `citra` folder.
|
||||
|
||||
{{< img src="entry/migrate-your-savefiles/ex_1.png" width="574px" height="142px">}}
|
||||
|
||||
2. Navigate to the ```app-x.x.x``` folder with the highest version number.
|
||||
<br></br>
|
||||
2. Navigate to the `app-x.x.x` folder with the highest version number.
|
||||
|
||||
{{< img src="entry/migrate-your-savefiles/ex_2.png" width="570px" height="497px">}}
|
||||
|
||||
3. Move the ```user``` folder to your desktop. **<u>Make sure the user folder no longer exists in the existing folder.</u>**
|
||||
3. Move the user` folder to your desktop. **<u>Make sure the user folder no longer exists in the existing folder.</u>**
|
||||
|
||||
4. Run ```citra-qt.exe```. The settings should now be reset, and Citra will begin using the new location. Now you can exit it.
|
||||
4. Run citra-qt.exe`. The settings should now be reset, and Citra will begin using the new location. Now you can exit
|
||||
it.
|
||||
|
||||
5. Press Windows + R, type ```explorer %appdata%```, this should bring up a Windows Explorer window in a ```Roaming``` folder. Navigate to the ```Citra ```folder.
|
||||
5. Press Windows + R, type `explorer %appdata%`, this should bring up a Windows Explorer window in a `Roaming` folder.
|
||||
Navigate to the ```Citra ```folder.
|
||||
|
||||
6. Move the contents of the ```user``` folder on your desktop to the ```Citra``` folder, overwrite any files if asked.
|
||||
6. Move the contents of the `user` folder on your desktop to the `Citra` folder, overwrite any files if asked.
|
||||
|
||||
Now, all of your settings and saves for Citra have been moved to the new location, which has the advantage of being able to be accessed by any new version of Citra, bringing stability improvements and storing your user data in a safe place.
|
||||
Now, all of your settings and saves for Citra have been moved to the new location, which has the advantage of being able
|
||||
to be accessed by any new version of Citra, bringing stability improvements and storing your user data in a safe place.
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
+++
|
||||
date = "2017-08-26T21:04:00-04:00"
|
||||
title = "Telemetry (And Why That's A Good Thing)"
|
||||
tags = [ "feature-update" ]
|
||||
author = "anodium"
|
||||
forum = 3095
|
||||
+++
|
||||
|
||||
Citra has some [issues](https://github.com/citra-emu/citra/issues), and by its
|
||||
nature as an open source project, they are visible to everyone and fixable by
|
||||
anyone. Unfortunately though, most contributions are made by
|
||||
[a small minority of developers](https://github.com/citra-emu/citra/graphs/contributors).
|
||||
These developers have found it difficult to prioritize their efforts, since the
|
||||
majority of issue reports are written scattered across Discord, Reddit, forums,
|
||||
IRC, and too many other places to count.
|
||||
|
||||
Because of this, the Citra team has put together a framework to report data about
|
||||
how Citra is used to our server, and use that data to discover what are the most
|
||||
popular games and hardware configurations, where emulated games crash in Citra
|
||||
most often, and more. We had considered including this in last month's progress
|
||||
report, but we decided that it would be best to publish this on its own, so it
|
||||
gets the attention it deserves. We're very aware that privacy is important to
|
||||
many of our users, and so from the earliest planning stage we knew we must be as
|
||||
transparent and open about this as possible.
|
||||
|
||||
The telemetry framework will collect information such as:
|
||||
|
||||
* Information about the version of Citra you are using
|
||||
* Performance data for the games you play
|
||||
* Your Citra configuration settings
|
||||
* Information about your computer hardware (e.g. GPU, CPU, and OS type)
|
||||
* Emulation errors and crash information
|
||||
|
||||
Not everyone is comfortable sharing information about their system, so we've made it easy to opt-out:
|
||||
|
||||
|
||||
{{< figure src="/images/entry/telemetry-and-why-thats-a-good-thing/optout1.png"
|
||||
alt="Alt, E, C"
|
||||
title="First, head to the Citra \"Emulation\" → \"Configure...\" menu." >}}
|
||||
|
||||
{{< figure src="/images/entry/telemetry-and-why-thats-a-good-thing/optout2.png"
|
||||
alt="Right arrow, Right arrow, Right arrow, Right arrow, Right arrow, Right arrow, Right arrow"
|
||||
title="Then, head into the \"Web\" tab." >}}
|
||||
|
||||
{{< figure src="/images/entry/telemetry-and-why-thats-a-good-thing/optout3.png"
|
||||
alt="Tab, Tab, Tab, Tab, Tab, Space"
|
||||
title="And finally, untick the box titled \"Share anonymous usage data with the Citra team\"." >}}
|
||||
|
||||
You may have also noticed the field titled "Telemetry ID" in the screenshots, this
|
||||
is an identifier generated randomly on install which is used instead of your IP
|
||||
address. This makes data collection entirely anonymous, unless you choose to log in.
|
||||
You can also reset your telemetry ID if you'd like by clicking "Regenerate". The
|
||||
new ID will also be completely random, and so it would be treated as a wholly new
|
||||
identity.
|
||||
|
||||
Telemetry is an extremely useful developer tool, as they allow the developer to
|
||||
be more aware of the users' needs and priorities accurately, rather than guessing.
|
||||
But it is only as useful as the data obtained, which is why we urge users to not
|
||||
opt-out, so the data can be as accurate and correct as possible. Just as innacurate
|
||||
measurements can damage a device during calibration, innacurate statistical data
|
||||
will only cause damage to Citra.
|
|
@ -7,7 +7,11 @@ coauthor = "tfarley"
|
|||
forum = 35
|
||||
+++
|
||||
|
||||
One of the big things everyone has been wondering about Citra is when it will be able to render games at HD resolutions. One of the great things about emulators is that they can surpass the limitations of the original console, especially when it comes to graphical fidelity. With the 3DS specifically, many beautifully detailed games are hidden behind staggeringly low resolution screens topping out at 400x240. With **Texture Forwarding** (from tfarley, based on yuriks early implementation), Citra can now output games at any resolution, and runs faster as well!
|
||||
One of the big things everyone has been wondering about Citra is when it will be able to render games at HD resolutions.
|
||||
One of the great things about emulators is that they can surpass the limitations of the original console, especially
|
||||
when it comes to graphical fidelity. With the 3DS specifically, many beautifully detailed games are hidden behind
|
||||
staggeringly low resolution screens topping out at 400x240. With **Texture Forwarding** (from tfarley, based on
|
||||
yuriks early implementation), Citra can now output games at any resolution, and runs faster as well!
|
||||
|
||||
{{< youtube 7XFcTqoZ3nk >}}
|
||||
|
||||
|
@ -15,11 +19,21 @@ One of the big things everyone has been wondering about Citra is when it will be
|
|||
|
||||
To understand Texture Forwarding, we've created a diagram to show what's actually going on.
|
||||
|
||||
{{< img src="entry/texture-forwarding-brings-hd-output-to-citra/citra-texture-forwarding.png" width="481px" height="367px" center="true" >}}
|
||||
<br></br>
|
||||
{{< figure src="/images/entry/texture-forwarding-brings-hd-output-to-citra/citra-texture-forwarding.png" >}}
|
||||
|
||||
The diagram is a simplified representation of the actual pipeline, as 3DS games perform multiple additional steps such as framebuffer copies between rendering and display - but the concept remains the same. The main idea is to keep framebuffers rendered by the HW Renderer as textures on the GPU as much as possible, to avoid the performance overhead of transferring them between the CPU and GPU as in the Slow Path. In most instances, the CPU never accesses (reads from/writes to) a rendered frame so it can safely stay on the GPU from rendering all the way through to ultimate display in Citra. This eliminates CPU/GPU sync points and makes the emulator faster overall.
|
||||
<br></br>
|
||||
In addition to a performance boost, Texture Forwarding also allows the HW Renderer to render and display at higher resolutions than the native 3DS when the pixel data is not accessed from anywhere else. But in the event that the memory region of some texture is reador writtenby the CPU, the renderer will fall back to the slow path and downsample the texture back to native resolution to ensure that the accesses are reflected accurately.
|
||||
The diagram is a simplified representation of the actual pipeline, as 3DS games perform multiple additional steps such
|
||||
as framebuffer copies between rendering and display - but the concept remains the same. The main idea is to keep
|
||||
framebuffers rendered by the HW Renderer as textures on the GPU as much as possible, to avoid the performance overhead
|
||||
of transferring them between the CPU and GPU as in the Slow Path. In most instances, the CPU never accesses
|
||||
(reads from/writes to) a rendered frame so it can safely stay on the GPU from rendering all the way through to
|
||||
ultimate display in Citra. This eliminates CPU/GPU sync points and makes the emulator faster overall.
|
||||
|
||||
In addition to a performance boost, Texture Forwarding also allows the HW Renderer to render and display at higher
|
||||
resolutions than the native 3DS when the pixel data is not accessed from anywhere else. But in the event that the
|
||||
memory region of some texture is read or written by the CPU, the renderer will fall back to the slow path and
|
||||
downsample the texture back to native resolution to ensure that the accesses are reflected accurately.
|
||||
|
||||
If you're interested in seeing just how nice some 3DS games look, [HD screenshots have been added to Citra's screenshots page!](https://citra-emu.org/screenshots) Or you can try it yourself on your 3DS games by downloading the latest build of Citra from the [download's page](https://citra-emu.org/page/download).
|
||||
If you're interested in seeing just how nice some 3DS games look,
|
||||
[HD screenshots have been added to Citra's screenshots page!](https://citra-emu.org/screenshots) Or you can try it
|
||||
yourself on your 3DS games by downloading the latest build of Citra from the
|
||||
[download's page](https://citra-emu.org/page/download).
|
||||
|
|
|
@ -7,6 +7,12 @@ coauthor = "flamboyant_ham"
|
|||
forum = 41
|
||||
+++
|
||||
|
||||
As you all know, the Nightly builds have been down for some time now due to the former maintainer not being around, but the issues have been resolved, and the Nightly builds are now available on our [downloads page](https://citra-emu.org/download/) once again! With downloads available for Windows, macOS, and Linux, you're no longer required to compile the build yourself.
|
||||
As you all know, the Nightly builds have been down for some time now due to the former maintainer not being around, but
|
||||
the issues have been resolved, and the Nightly builds are now available on our
|
||||
[downloads page](https://citra-emu.org/download/) once again! With downloads available for Windows, macOS, and Linux,
|
||||
you're no longer required to compile the build yourself.
|
||||
|
||||
Likewise, we'd like to remind all users that any bugs found within Citra, or during emulation, be reported from the Nightly builds, and not the Bleeding Edge ones. From hereon out, support for the latter will no longer be given. If you believe you've found a bug in Bleeding Edge, please retest on the latest Nightly build. Thank you everyone for your patience, and Happy New Year!
|
||||
Likewise, we'd like to remind all users that any bugs found within Citra, or during emulation, be reported from the
|
||||
Nightly builds, and not the Bleeding Edge ones. From hereon out, support for the latter will no longer be given. If
|
||||
you believe you've found a bug in Bleeding Edge, please retest on the latest Nightly build. Thank you everyone for
|
||||
your patience, and Happy New Year!
|
||||
|
|
|
@ -5,19 +5,21 @@ author = "thekoopakingdom"
|
|||
forum = 39
|
||||
+++
|
||||
|
||||
If you haven't heard of [Discord](https://discordapp.com/) yet, it's basically an alternative to Skype, featuring servers with both voice and text chat. You can use it in your browser, download the desktop program, or get the mobile app.
|
||||
If you haven't heard of [Discord](https://discordapp.com/) yet, it's basically an alternative to Skype, featuring
|
||||
servers with both voice and text chat. You can use it in your browser, download the desktop program, or get the mobile
|
||||
app.
|
||||
|
||||
If you don't have an account already, you can make one for free [here](https://discordapp.com/register).
|
||||
|
||||
Once you've done that, you can join Citra's official server by going [here](https://discord.gg/fZwvKPu).
|
||||
Once you've done that, you can join Citra's official server by going [here](/discord/).
|
||||
|
||||
There are 5 channels:
|
||||
|
||||
* #read-first - A read-only introduction to the server, and announcements.
|
||||
* #citra-general - Any discussion related to Citra.
|
||||
* #citra-support - If you are having trouble with Citra, you can ask for help here. **Please read #read-first, first.**
|
||||
* #dumping-support - Support for dumping games/system files for Citra.
|
||||
* #offtopic - Anything not related to Citra that doesn't belong in #citra-general goes here.
|
||||
* \#read-first - A read-only introduction to the server, and announcements.
|
||||
* \#citra-general - Any discussion related to Citra.
|
||||
* \#citra-support - If you are having trouble with Citra, you can ask for help here. **Please read #read-first, first.**
|
||||
* \#dumping-support - Support for dumping games/system files for Citra.
|
||||
* \#offtopic - Anything not related to Citra that doesn't belong in #citra-general goes here.
|
||||
|
||||
The [Citra](https://citra-emu.org/rules/) Community Rules also apply to this server.
|
||||
|
||||
|
|
|
@ -5,28 +5,32 @@ author = "flamesage"
|
|||
forum = 8
|
||||
+++
|
||||
|
||||
Welcome to the brand new Citra website! This new site has been a sort of secret project off and on for over a year now. A lot of hard work, a few false starts, but here we are! This has been a big team effort - we'd like to especially thank [Flame Sage](https://community.citra-emu.org/users/flamesage/activity), the primary architect behind the new website backend; [MaJoR](https://community.citra-emu.org/users/mayimilae/activity) for the design and artwork, and lastly jchadwick for his early on role in the project. Here's a brief overview of some of our new features!
|
||||
Welcome to the brand new Citra website! This new site has been a sort of secret project off and on for over a year now.
|
||||
A lot of hard work, a few false starts, but here we are! This has been a big team effort - we'd like to especially
|
||||
thank [Flame Sage](https://community.citra-emu.org/users/flamesage/activity), the primary architect behind the new
|
||||
website backend; [MaJoR](https://community.citra-emu.org/users/mayimilae/activity) for the design and artwork, and
|
||||
lastly jchadwick for his early on role in the project. Here's a brief overview of some of our new features!
|
||||
|
||||
|
||||
**[Blog](https://citra-emu.org):** Citra now *finally* has a platform to share information with everyone directly! It
|
||||
will allow Citra to communicate directly to users and fans in long form, fully exploring 3DS emulation in ways that
|
||||
were impossible to express before. An article is already up talking about the past year of development, and more
|
||||
will come!
|
||||
|
||||
**[Blog](https://citra-emu.org):** Citra now *finally* has a platform to share information with everyone directly! It will allow Citra to communicate directly to users and fans in long form, fully exploring 3DS emulation in ways that were impossible to express before. An article is already up talking about the past year of development, and more will come!
|
||||
**[Community](https://community.citra-emu.org/):** Citra now has its own discussion forum! It is now open, so come on
|
||||
everyone and join! Instead of the typical forum software, we are using a brand new open source forum software that
|
||||
is focused on streamlining and simplifying bulletin boards. It's a little different from what you might be used to,
|
||||
but it is a joy to use!
|
||||
|
||||
|
||||
**[Wiki](https://citra-emu.org/wiki/Home):** The site has it's own wiki! But not a mediawiki - select articles from
|
||||
Github can be elevated here for easy access to user-update guides and other materials. In time, it will make Citra
|
||||
much easier to use.
|
||||
|
||||
**[Community](https://community.citra-emu.org/):** Citra now has its own discussion forum! It is now open, so come on everyone and join! Instead of the typical forum software, we are using a brand new open source forum software that is focused on streamlining and simplifying bulletin boards. It's a little different from what you might be used to, but it is a joy to use!
|
||||
|
||||
|
||||
|
||||
**[Wiki](https://citra-emu.org/wiki/Home):** The site has it's own wiki! But not a mediawiki - select articles from github can be elevated here for easy access to user-update guides and other materials. In time, it will make Citra much easier to use.
|
||||
|
||||
|
||||
|
||||
**[Screenshots](https://citra-emu.org/screenshots):** We have our own screenshots gallery, which will give us a *lot* more room for a lot more screenshots! With easy navigation and viewing to boot.
|
||||
|
||||
|
||||
**[Screenshots](https://citra-emu.org/screenshots):** We have our own screenshots gallery, which will give us a *lot*
|
||||
more room for a lot more screenshots! With easy navigation and viewing to boot.
|
||||
|
||||
**Logo:** And finally, this is the official reveal of our new logo!
|
||||
|
||||
{{< img src="entry/welcome-to-the-new-citra/citralogoforarticle.jpg" width="640px" height="320px" center="true" >}}
|
||||
|
||||
There's a LOT more work to be done, so things are definitely a work in progress. For example, a new download page with archives is high on our list! But we're going to keep working hard and keep making things better.
|
||||
There's a LOT more work to be done, so things are definitely a work in progress. For example, a new download page with
|
||||
archives is high on our list! But we're going to keep working hard and keep making things better.
|
||||
|
|
|
@ -8,10 +8,22 @@ forum = 54
|
|||
|
||||
As we approach the first birthday of Citra's website, we'd like to announce yet another project infrastructure update:
|
||||
|
||||
**We've decided to launch a [new forum](http://community.citra-emu.org/) based on the [Discourse](https://www.discourse.org/) forum software!**
|
||||
**We've decided to launch a [new forum](http://community.citra-emu.org/) based on the
|
||||
[Discourse](https://www.discourse.org/) forum software!**
|
||||
|
||||
When we first introduced the new website back in February of 2016, we chose to use [Flarum](http://flarum.org/) over more classic forums used on other websites (such as phpBB, MyBB, or vBulletin). The reason for this was because Flarum was a much more modern platform, with better mobile support, and a attractive and innovative UI. It seemingly had a very promising future, receiving multiple large updates in a very short timeframe. But while it was great to use at first, it ultimately left us wanting some critical features that never seemed to come - such as the ability to send private messages.
|
||||
When we first introduced the new website back in February of 2016, we chose to use [Flarum](http://flarum.org/) over
|
||||
more classic forums used on other websites (such as phpBB, MyBB, or vBulletin). The reason for this was because Flarum
|
||||
was a much more modern platform, with better mobile support, and a attractive and innovative UI. It seemingly had a
|
||||
very promising future, receiving multiple large updates in a very short timeframe. But while it was great to use at
|
||||
first, it ultimately left us wanting some critical features that never seemed to come - such as the ability to send
|
||||
private messages.
|
||||
|
||||
Meet [Discourse](https://www.discourse.org/), an open source forum platform with the features that we need. Not only does it improve our ability to moderate, but the every day user experience should also be enhanced. Discourse is a widely used and established platform, used by such communities as [Imgur](https://community.imgur.com/), [Twitter](https://twittercommunity.com/), [Github](https://discuss.atom.io/), [Ubuntu](http://discourse.ubuntu.com/), and [more](https://www.discourse.org/faq/customers/). The layout of the new forums are simple, users of Flarum should have no problem getting used to it!
|
||||
Meet [Discourse](https://www.discourse.org/), an open source forum platform with the features that we need. Not only
|
||||
does it improve our ability to moderate, but the every day user experience should also be enhanced. Discourse is a
|
||||
widely used and established platform, used by such communities as [Imgur](https://community.imgur.com/),
|
||||
[Twitter](https://twittercommunity.com/), [Github](https://discuss.atom.io/), [Ubuntu](http://discourse.ubuntu.com/),
|
||||
and [more](https://www.discourse.org/faq/customers/). The layout of the new forums are simple, users of Flarum should
|
||||
have no problem getting used to it!
|
||||
|
||||
You can visit the new forums at https://community.citra-emu.org/, come say Hello! You'll need to create a new account, but we now support using your Google or GitHub credentials to log in!
|
||||
You can visit the new forums at https://community.citra-emu.org/, come say Hello! You'll need to create a new account,
|
||||
but we now support using your Google or GitHub credentials to log in!
|
||||
|
|
|
@ -33,7 +33,7 @@ This is an English only forum, please do not post in any other language. If you
|
|||
|
||||
## Repercussions
|
||||
|
||||
First and foremost, breaking a rule related to piracy will result in an immediate suspension of your account, and likely the deletion of the infringing post.
|
||||
First and foremost, breaking a rule related to piracy will result in a warning from the moderators, and likely the deletion of the infringing post if it has links to copyrighted material.
|
||||
|
||||
The moderation staff will discuss prolonged or permanent suspension beforehand on every case, with the only exceptions being SPAM, or anything imminently harmful such as harassment.
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
"tfarley": { "key": "tfarley", "name": "tfarley", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/citrabot/120/28_1.png" },
|
||||
"merrymage": { "key": "merrymage", "name": "Merry Mage", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/citrabot/120/28_1.png" },
|
||||
"jroweboy": { "key": "jroweboy", "name": "jroweboy", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/jroweboy/120/30_1.png" },
|
||||
"jmc47": { "key": "jmc47", "name": "JMC47", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/citrabot/120/28_1.png" },
|
||||
"jmc47": { "key": "jmc47", "name": "JMC47", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/jmc47/45/1487_1.png" },
|
||||
"anodium": { "key": "anodium", "name": "anodium", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/anodium/120/485_1.png"},
|
||||
"saphiresurf": {"key": "saphiresurf", "name": "saphiresurf", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/saphiresurf/120/695_1.png"}
|
||||
"saphiresurf": {"key": "saphiresurf", "name": "saphiresurf", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/saphiresurf/120/695_1.png"},
|
||||
"CaptV0rt3x": {"key": "CaptV0rt3x", "name": "CaptV0rt3x", "avatar": "https://community.citra-emu.org/user_avatar/community.citra-emu.org/captv0rt3x/120/4767_1.png"}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"0": { "name": "Perfect", "color": "#5c93ed", "description": "Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed." },
|
||||
"1": { "name": "Great", "color": "#47d35c", "description": "Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds." },
|
||||
"2": { "name": "Okay", "color": "#94b242", "description": "Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds." },
|
||||
"3": { "name": "Bad", "color": "#f2d624", "description": "Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds." },
|
||||
"4": { "name": "Intro/Menu", "color": "red", "description": "Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen." },
|
||||
"5": { "name": "Won't Boot", "color": "#828282", "description": "The game crashes when attempting to startup." },
|
||||
"99": { "name": "Not Tested", "color": "black", "description": "This game has not yet been tested." }
|
||||
"0": { "key": "0", "name": "Perfect", "color": "#5c93ed", "description": "Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without any workarounds needed." },
|
||||
"1": { "key": "1", "name": "Great", "color": "#47d35c", "description": "Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds." },
|
||||
"2": { "key": "2", "name": "Okay", "color": "#94b242", "description": "Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds." },
|
||||
"3": { "key": "3", "name": "Bad", "color": "#f2d624", "description": "Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds." },
|
||||
"4": { "key": "4", "name": "Intro/Menu", "color": "red", "description": "Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen." },
|
||||
"5": { "key": "5", "name": "Won't Boot", "color": "#828282", "description": "The game crashes when attempting to startup." },
|
||||
"99": { "key": "99", "name": "Not Tested", "color": "black", "description": "The game has not yet been tested." }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"3ds": { "key": "3ds", "name": "3DS Game" },
|
||||
"dsiware": { "key": "dsiware", "name": "DSI Ware" },
|
||||
"eshop": { "key": "eshop", "name": "eShop" },
|
||||
"vc": { "key": "vc", "name": "Virtual Console" }
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"nes": { "key": "nes", "name": "Nintendo Entertainment System" },
|
||||
"snes": { "key": "snes", "name": "Super Nintendo Entertainment System" },
|
||||
"gb": { "key": "gb", "name": "Game Boy" },
|
||||
"gbc": { "key": "gbc", "name": "Game Boy Color" },
|
||||
"gba": { "key": "gba", "name": "Game Boy Advance" },
|
||||
"gg": { "key": "gg", "name": "Game Gear" }
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
[home]
|
||||
other = "Home"
|
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 695 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 903 KiB |
After Width: | Height: | Size: 1.4 MiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 584 KiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 796 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 227 KiB |
After Width: | Height: | Size: 218 KiB |
After Width: | Height: | Size: 319 KiB |
|
@ -0,0 +1,95 @@
|
|||
_Wireless Support_ is one of those features that were so surprising to see that even the testers were wondering if it was real. But several developers have banded together to put together this amazing feature.
|
||||
|
||||
<div style="position:relative;height:0;padding-bottom:65%"><iframe src="https://www.youtube.com/embed/bAy-d6Nztxw?ecver=2" style="position:absolute;width:100%;height:100%;left:0" width="641" height="360" frameborder="0" allowfullscreen></iframe></div>
|
||||
|
||||
The Nintendo 3DS heavily relies on wireless for its slew of multiplayer compatible titles. Considering that so many games feel empty without their multiplayer features, we're excited to announce that in select titles, you'll be able to play together with friends in the latest Canary builds of Citra!
|
||||
|
||||
![](/content/images/2017/10/LetsBattle.png)
|
||||
|
||||
#### Bringing Multiplayer to Citra
|
||||
|
||||
Putting together this feature was a massive endeavor between subv, jroweboy and B3N30. It went through several stages of development, from actually reverse-engineering how wireless worked in games, to implementing those features in Citra, and then implementing an infrastructure so that even casual users can take advantage of multiplayer features.
|
||||
|
||||
This emulates the 3DSes ability to do *local wireless* multiplayer. As such, it doesn't rely on Nintendo's server and does not require a Nintendo Network ID. Unlike real 3DSes, this feature can now be taken online thanks to a complex server infrastructure.
|
||||
|
||||
Unlike single console netplay used in most emulators, users won't have to worry about desyncs, synchronizing saves, or any other issues typical of netplay. Each user is using their instance of Citra as a unique emulated 3DS that is communicating with everyone else through that particular server.
|
||||
|
||||
![](/content/images/2017/10/GameBrowser.jpg)
|
||||
|
||||
Currently, servers created in Citra can hold up to 16 players. Users are also provided with a dedicated server which allows for higher player counts. Extremely high player counts should be avoided for now due to bandwidth issues. In this initial release, each connected Citra instance sends raw packets to the host (or server) and the server then forwards those packets to every single client. As such, with each player added, the bandwidth requirements increase greatly.
|
||||
|
||||
While hundreds of games support wireless connectivity, compatibility is limited in the initial release. Tons of titles were tested, but only a handful came up as working properly. Note games may handle latency differently and your experience may vary.
|
||||
|
||||
### The Server Browser
|
||||
|
||||
In order to get together with other players, you're going to have to join the same room with Citra's server browser. Creating and joining servers is extremely easy in Citra and can be done in just a few clicks. If you're a verified user, you can create a public game through the traversal server for people to join. These public games can be seen by **anyone** on the server browser. If you just want your friends to join without the hassle of port-forwarding and sending an IP, you can also put a password on publicly listed games.
|
||||
|
||||
Unverified users aren't left without options, though - they still have the ability to create unlisted games directly connecting and can join any hosted server.
|
||||
|
||||
Do note that verified users **will** have their privileges revoked for violating any site policies while on the server chatroom. Please respect the *recommended game* listed in publicly hosted games, as even unrelated games will add to the bandwidth load.
|
||||
|
||||
### Wireless Compatibility
|
||||
#### Works Like a Charm
|
||||
##### Super Smash Bros. for 3DS
|
||||
|
||||
_Super Smash Brother's_ local play works perfectly in Citra for up to four players. Because the game expects all players to be running in lockstep, users will need to maintain full speed for a stable connection. Some stages, such as the pictochat stage, can run full speed even on moderate computers.
|
||||
|
||||
![](/content/images/2017/10/SmashLocal.png)
|
||||
|
||||
##### Pokèmon X/Y, Pokèmon Omega Ruby/Alpha Sapphire, and Pokèmon Sun/Moon
|
||||
|
||||
Almost everything works perfectly in the _Pokèmon_ games. The only thing that fails is adding friends - so try to stay away from that. Users can battle, trade, and watch passerbys as they show up or leave on the local wireless server.
|
||||
|
||||
Because of compatibility issues in general with X and Y, using wireless support may be problematic for those two titles.
|
||||
|
||||
![](/content/images/2017/10/ChallengePok.png)
|
||||
|
||||
##### New Super Mario Bros. 2
|
||||
|
||||
_New Super Mario Bros. 2_ seems to be perfectly. Users on the same server can search for partners and join up just fine.
|
||||
|
||||
![](/content/images/2017/10/NSMB2.jpg)
|
||||
|
||||
#### Functional But Flawed
|
||||
|
||||
##### Luigi's Mansion: Dark Moon
|
||||
|
||||
This title has perfectly functional wireless support for trying to tackle the "Scarescraper"! Unfortunately, the game is so demanding that getting a fun experience out of it is near impossible.
|
||||
|
||||
![](/content/images/2017/10/LuigisMansionLobby.png)
|
||||
|
||||
##### Monster Hunter 3U and 4U
|
||||
|
||||
The _Monster Hunter_ games are extremely demanding in Citra, but wireless support _does_ somewhat work. A second player can join a game, share quests and trade guild cards. But, the game supports up to four local players on console, and anything more than two causes disconnections in Citra.
|
||||
|
||||
![](https://cdn.discordapp.com/attachments/334046137642254337/369924205975830528/image.png)
|
||||
|
||||
#### Incompatible
|
||||
|
||||
For various reasons, the following games were tested and do not work. Also note that Download Play and Spotpass titles do not work due to limitations in what Citra currently emulates.
|
||||
|
||||
* Mario Party Island Tour
|
||||
* Mario Party Star Rush
|
||||
* The Legend of Zelda: TriForce Heroes
|
||||
* Mario Kart 7
|
||||
* Tetris Ultimate
|
||||
* Code of Princess
|
||||
* Sonic Generations
|
||||
* Asphalt Assault 3D
|
||||
* Ridge Racer 3D
|
||||
* Monster Hunter Generations
|
||||
* Monster Hunter X
|
||||
* Monster Hunter XX
|
||||
* Street Fighter IV
|
||||
* Kirby Triple Deluxe
|
||||
* Dragon Quest Monsters: Terry
|
||||
* Resident Evil Mercenaries 3D
|
||||
* Dragon Quest Monsters: Joker 3 Pro
|
||||
* Formula 1 2011
|
||||
* Kirby Fighters Deluxe
|
||||
* Planet Crashers
|
||||
|
||||
### Going Forward
|
||||
|
||||
After the months of the work put into making _Wireless Support_ a reality, we're excited to see it finally brought into the public eye. While only a handful of games work in this initial release, we're hoping to bring support to more titles in the future, as well as optimizing the netcode for lower bandwidth usage and bringing even bigger servers to the table.
|
||||
|
After Width: | Height: | Size: 2.0 MiB |
After Width: | Height: | Size: 4.0 MiB |
After Width: | Height: | Size: 3.5 MiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 1.7 MiB |
After Width: | Height: | Size: 661 KiB |
After Width: | Height: | Size: 620 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 2.3 MiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 5.4 MiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 29 KiB |