Compare commits
16 commits
v0.18.0-al
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 81decf2b71 | |||
| 4575830857 | |||
| ae802493a0 | |||
| f910e6bdbb | |||
| ed2f3f7abc | |||
| 2b06b79bbf | |||
| 98a27e2f53 | |||
| 737d1cf2e0 | |||
| 7ae20789a9 | |||
| 17fef2c5d4 | |||
| aaa5803e6b | |||
| 0cc3ae9709 | |||
| 046f5e0fdb | |||
| 135fd9110f | |||
| 1ab2a291d2 | |||
| da7f072365 |
|
|
@ -1,15 +1,15 @@
|
||||||
# NETfishing Asset License 1.1
|
# straywild Asset License 1.1
|
||||||
|
|
||||||
Copyright © 2026 Woofmeow. All rights reserved except for the permissions
|
Copyright © 2026 Woofmeow. All rights reserved except for the permissions
|
||||||
expressly granted below.
|
expressly granted below.
|
||||||
|
|
||||||
## 1. Scope
|
## 1. Scope
|
||||||
|
|
||||||
This license applies to original NETfishing artwork, graphics, textures,
|
This license applies to original straywild artwork, graphics, textures,
|
||||||
models, animations, music, sound recordings, narrative content, visual
|
models, animations, music, sound recordings, narrative content, visual
|
||||||
designs, characters, and other creative assets owned by the NETfishing owners
|
designs, characters, and other creative assets owned by the straywild owners
|
||||||
or licensed to them with authority to sublicense, publishing as Woofmeow (the
|
or licensed to them with authority to sublicense, publishing as Woofmeow (the
|
||||||
**“NETfishing Assets”**).
|
**“straywild Assets”**).
|
||||||
|
|
||||||
It does not apply to:
|
It does not apply to:
|
||||||
|
|
||||||
|
|
@ -17,77 +17,77 @@ It does not apply to:
|
||||||
- third-party material identified in the source repository's
|
- third-party material identified in the source repository's
|
||||||
`docs/ATTRIBUTION.md` or the packaged `ATTRIBUTION.md` notice;
|
`docs/ATTRIBUTION.md` or the packaged `ATTRIBUTION.md` notice;
|
||||||
- material accompanied by a different license; or
|
- material accompanied by a different license; or
|
||||||
- the NETfishing and Woofmeow names and logos, which are addressed in
|
- the straywild and Woofmeow names and logos, which are addressed in
|
||||||
`TRADEMARKS.md`.
|
`TRADEMARKS.md`.
|
||||||
|
|
||||||
Repository location alone does not change third-party ownership or licensing.
|
Repository location alone does not change third-party ownership or licensing.
|
||||||
|
|
||||||
## 2. Definitions
|
## 2. Definitions
|
||||||
|
|
||||||
**Official NETfishing Software** means:
|
**Official straywild Software** means:
|
||||||
|
|
||||||
- an unmodified binary release published by the NETfishing owners through an
|
- an unmodified binary release published by the straywild owners through an
|
||||||
official NETfishing distribution channel; or
|
official straywild distribution channel; or
|
||||||
- a build made from an unmodified official NETfishing source release or tagged
|
- a build made from an unmodified official straywild source release or tagged
|
||||||
revision.
|
revision.
|
||||||
|
|
||||||
**Mod** means a non-standalone add-on created to operate with Official
|
**Mod** means a non-standalone add-on created to operate with Official
|
||||||
NETfishing Software. A Mod may add, replace, or alter content loaded by the
|
straywild Software. A Mod may add, replace, or alter content loaded by the
|
||||||
Official NETfishing Software, but it may not redistribute a replacement copy
|
Official straywild Software, but it may not redistribute a replacement copy
|
||||||
of the game or represent a fork, clone, sequel, or separate game.
|
of the game or represent a fork, clone, sequel, or separate game.
|
||||||
|
|
||||||
**Contribution Fork** means a source-control fork or clone of an official
|
**Contribution Fork** means a source-control fork or clone of an official
|
||||||
NETfishing source repository that is created and maintained in good faith
|
straywild source repository that is created and maintained in good faith
|
||||||
primarily to prepare, test, review, or submit changes for possible inclusion
|
primarily to prepare, test, review, or submit changes for possible inclusion
|
||||||
in Official NETfishing Software. It does not include a fork presented or
|
in Official straywild Software. It does not include a fork presented or
|
||||||
developed as an independent game, community edition, replacement distribution,
|
developed as an independent game, community edition, replacement distribution,
|
||||||
or ongoing product separate from the official NETfishing project.
|
or ongoing product separate from the official straywild project.
|
||||||
|
|
||||||
## 3. Permission to use the official game
|
## 3. Permission to use the official game
|
||||||
|
|
||||||
You may reproduce NETfishing Assets as technically necessary to install, run,
|
You may reproduce straywild Assets as technically necessary to install, run,
|
||||||
back up, and privately modify a lawfully obtained copy of Official NETfishing
|
back up, and privately modify a lawfully obtained copy of Official straywild
|
||||||
Software.
|
Software.
|
||||||
|
|
||||||
You may capture, publish, and monetize screenshots, gameplay videos,
|
You may capture, publish, and monetize screenshots, gameplay videos,
|
||||||
livestreams, reviews, tutorials, and similar commentary showing a lawfully
|
livestreams, reviews, tutorials, and similar commentary showing a lawfully
|
||||||
obtained copy of NETfishing. This permission does not authorize redistribution
|
obtained copy of straywild. This permission does not authorize redistribution
|
||||||
of the source asset files or imply endorsement.
|
of the source asset files or imply endorsement.
|
||||||
|
|
||||||
## 4. Community Mod license
|
## 4. Community Mod license
|
||||||
|
|
||||||
Subject to this license, you may create, modify, and distribute NETfishing
|
Subject to this license, you may create, modify, and distribute straywild
|
||||||
Assets solely as part of a Mod for Official NETfishing Software.
|
Assets solely as part of a Mod for Official straywild Software.
|
||||||
|
|
||||||
This permission is worldwide, nonexclusive, royalty-free, and available for
|
This permission is worldwide, nonexclusive, royalty-free, and available for
|
||||||
as long as you comply with this license. It permits only the copies of
|
as long as you comply with this license. It permits only the copies of
|
||||||
NETfishing Assets reasonably necessary for the Mod to function. It does not
|
straywild Assets reasonably necessary for the Mod to function. It does not
|
||||||
permit distributing the original game, a substantially complete collection of
|
permit distributing the original game, a substantially complete collection of
|
||||||
its assets, or a general-purpose asset pack.
|
its assets, or a general-purpose asset pack.
|
||||||
|
|
||||||
A distributed Mod must:
|
A distributed Mod must:
|
||||||
|
|
||||||
1. require a separately obtained copy of Official NETfishing Software;
|
1. require a separately obtained copy of Official straywild Software;
|
||||||
2. be presented as unofficial community content;
|
2. be presented as unofficial community content;
|
||||||
3. include the following notice in its documentation or distribution page:
|
3. include the following notice in its documentation or distribution page:
|
||||||
|
|
||||||
> Contains or adapts NETfishing assets © 2026 Woofmeow, used under the
|
> Contains or adapts straywild assets © 2026 Woofmeow, used under the
|
||||||
> NETfishing Asset License 1.1. This Mod is unofficial and is not endorsed
|
> straywild Asset License 1.1. This Mod is unofficial and is not endorsed
|
||||||
> by Woofmeow.
|
> by Woofmeow.
|
||||||
|
|
||||||
4. identify material created by the Mod author separately from NETfishing
|
4. identify material created by the Mod author separately from straywild
|
||||||
Assets; and
|
Assets; and
|
||||||
5. comply with `TRADEMARKS.md`.
|
5. comply with `TRADEMARKS.md`.
|
||||||
|
|
||||||
Mods may be shared without charge and may accept voluntary donations that do
|
Mods may be shared without charge and may accept voluntary donations that do
|
||||||
not purchase access, features, or preferential treatment. Selling a Mod,
|
not purchase access, features, or preferential treatment. Selling a Mod,
|
||||||
charging for access to it, licensing it commercially, or using NETfishing
|
charging for access to it, licensing it commercially, or using straywild
|
||||||
Assets in paid products requires separate written permission from both
|
Assets in paid products requires separate written permission from both
|
||||||
NETfishing owners.
|
straywild owners.
|
||||||
|
|
||||||
## 5. Contribution Fork license
|
## 5. Contribution Fork license
|
||||||
|
|
||||||
Subject to this license, you may reproduce, modify, and distribute NETfishing
|
Subject to this license, you may reproduce, modify, and distribute straywild
|
||||||
Assets within a Contribution Fork. You may also make the nonpublic builds
|
Assets within a Contribution Fork. You may also make the nonpublic builds
|
||||||
reasonably necessary to develop, test, and review its proposed contribution.
|
reasonably necessary to develop, test, and review its proposed contribution.
|
||||||
|
|
||||||
|
|
@ -99,8 +99,8 @@ fork are permitted distributions.
|
||||||
A Contribution Fork must:
|
A Contribution Fork must:
|
||||||
|
|
||||||
1. remain primarily directed toward preparing changes for possible inclusion
|
1. remain primarily directed toward preparing changes for possible inclusion
|
||||||
in the official NETfishing project;
|
in the official straywild project;
|
||||||
2. preserve this license and the official NETfishing project's applicable
|
2. preserve this license and the official straywild project's applicable
|
||||||
attribution, third-party license, and copyright notices;
|
attribution, third-party license, and copyright notices;
|
||||||
3. remain visibly linked to or identified as a fork of the official source
|
3. remain visibly linked to or identified as a fork of the official source
|
||||||
repository and not be presented as official or endorsed;
|
repository and not be presented as official or endorsed;
|
||||||
|
|
@ -109,63 +109,63 @@ A Contribution Fork must:
|
||||||
contribution;
|
contribution;
|
||||||
5. not publish general-audience binaries, releases, packages, or downloads,
|
5. not publish general-audience binaries, releases, packages, or downloads,
|
||||||
operate a persistent public alternative service, or monetize access;
|
operate a persistent public alternative service, or monetize access;
|
||||||
6. not distribute the NETfishing Assets as a standalone extraction, archive,
|
6. not distribute the straywild Assets as a standalone extraction, archive,
|
||||||
or general-purpose asset pack; and
|
or general-purpose asset pack; and
|
||||||
7. comply with `TRADEMARKS.md`.
|
7. comply with `TRADEMARKS.md`.
|
||||||
|
|
||||||
Temporary access-controlled servers may be operated when reasonably necessary
|
Temporary access-controlled servers may be operated when reasonably necessary
|
||||||
to test a proposed contribution. They may not be promoted or maintained as a
|
to test a proposed contribution. They may not be promoted or maintained as a
|
||||||
public alternative to Official NETfishing Software or its services.
|
public alternative to Official straywild Software or its services.
|
||||||
|
|
||||||
Submitting work from a Contribution Fork is governed separately by
|
Submitting work from a Contribution Fork is governed separately by
|
||||||
`CONTRIBUTOR-TERMS.md` and does not require the NETfishing owners to accept the
|
`CONTRIBUTOR-TERMS.md` and does not require the straywild owners to accept the
|
||||||
work. Declining or closing a proposed contribution does not retroactively
|
work. Declining or closing a proposed contribution does not retroactively
|
||||||
invalidate good-faith use under this section. A compliant Contribution Fork
|
invalidate good-faith use under this section. A compliant Contribution Fork
|
||||||
may remain publicly accessible as an archival development record, but it may
|
may remain publicly accessible as an archival development record, but it may
|
||||||
not be repurposed for continued development or distribution of a separate
|
not be repurposed for continued development or distribution of a separate
|
||||||
product containing NETfishing Assets.
|
product containing straywild Assets.
|
||||||
|
|
||||||
## 6. Uses not permitted
|
## 6. Uses not permitted
|
||||||
|
|
||||||
Except as expressly permitted by Sections 3, 4, and 5 or by separate written
|
Except as expressly permitted by Sections 3, 4, and 5 or by separate written
|
||||||
permission from both NETfishing owners, you may not use or distribute
|
permission from both straywild owners, you may not use or distribute
|
||||||
NETfishing Assets:
|
straywild Assets:
|
||||||
|
|
||||||
- in a fork, clone, remake, sequel, or standalone game that is not a qualifying
|
- in a fork, clone, remake, sequel, or standalone game that is not a qualifying
|
||||||
Contribution Fork;
|
Contribution Fork;
|
||||||
- with a modified distribution of the GPL-covered NETfishing code that is not
|
- with a modified distribution of the GPL-covered straywild code that is not
|
||||||
Official NETfishing Software, except for nonpublic contribution-testing
|
Official straywild Software, except for nonpublic contribution-testing
|
||||||
builds permitted by Section 5;
|
builds permitted by Section 5;
|
||||||
- in another game, application, asset library, template, or merchandise;
|
- in another game, application, asset library, template, or merchandise;
|
||||||
- as a substantially complete asset extraction or archive;
|
- as a substantially complete asset extraction or archive;
|
||||||
- in a way that implies sponsorship, endorsement, or official status;
|
- in a way that implies sponsorship, endorsement, or official status;
|
||||||
- to register a confusingly similar trademark, domain, account, or product
|
- to register a confusingly similar trademark, domain, account, or product
|
||||||
identity; or
|
identity; or
|
||||||
- under terms that claim ownership of the NETfishing Assets themselves.
|
- under terms that claim ownership of the straywild Assets themselves.
|
||||||
|
|
||||||
The GPL permits forks and redistribution of the GPL-covered code. Except for a
|
The GPL permits forks and redistribution of the GPL-covered code. Except for a
|
||||||
qualifying Contribution Fork under Section 5, this asset license does not
|
qualifying Contribution Fork under Section 5, this asset license does not
|
||||||
permit those forks to carry NETfishing Assets. A code fork that is not a
|
permit those forks to carry straywild Assets. A code fork that is not a
|
||||||
Contribution Fork must remove or replace the NETfishing Assets and reserved
|
Contribution Fork must remove or replace the straywild Assets and reserved
|
||||||
branding unless both owners grant separate written permission.
|
branding unless both owners grant separate written permission.
|
||||||
|
|
||||||
## 7. Ownership of Mods and contribution work
|
## 7. Ownership of Mods and contribution work
|
||||||
|
|
||||||
You retain ownership of your original Mod material and original material
|
You retain ownership of your original Mod material and original material
|
||||||
created in a Contribution Fork. The NETfishing owners retain ownership of the
|
created in a Contribution Fork. The straywild owners retain ownership of the
|
||||||
NETfishing Assets and adaptations of those assets to the extent provided by
|
straywild Assets and adaptations of those assets to the extent provided by
|
||||||
applicable law.
|
applicable law.
|
||||||
|
|
||||||
This license does not require you to assign or submit your original material.
|
This license does not require you to assign or submit your original material.
|
||||||
It also does not grant you ownership of the underlying NETfishing Assets. If
|
It also does not grant you ownership of the underlying straywild Assets. If
|
||||||
you intentionally submit material for inclusion in NETfishing,
|
you intentionally submit material for inclusion in straywild,
|
||||||
`CONTRIBUTOR-TERMS.md` applies separately.
|
`CONTRIBUTOR-TERMS.md` applies separately.
|
||||||
|
|
||||||
## 8. Termination and cure
|
## 8. Termination and cure
|
||||||
|
|
||||||
Your permissions under this license terminate automatically if you violate
|
Your permissions under this license terminate automatically if you violate
|
||||||
its terms. They are reinstated provisionally when you stop the violation and
|
its terms. They are reinstated provisionally when you stop the violation and
|
||||||
permanently if both NETfishing owners do not notify you of the violation
|
permanently if both straywild owners do not notify you of the violation
|
||||||
within sixty days after it has been cured.
|
within sixty days after it has been cured.
|
||||||
|
|
||||||
Termination does not limit remedies available for activity outside this
|
Termination does not limit remedies available for activity outside this
|
||||||
|
|
@ -173,15 +173,15 @@ license.
|
||||||
|
|
||||||
## 9. No warranty
|
## 9. No warranty
|
||||||
|
|
||||||
THE NETFISHING ASSETS ARE PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND,
|
THE straywild ASSETS ARE PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND,
|
||||||
EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
PARTICULAR PURPOSE, TITLE, OR NON-INFRINGEMENT. TO THE MAXIMUM EXTENT
|
PARTICULAR PURPOSE, TITLE, OR NON-INFRINGEMENT. TO THE MAXIMUM EXTENT
|
||||||
PERMITTED BY LAW, THE OWNERS WILL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR
|
PERMITTED BY LAW, THE OWNERS WILL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR
|
||||||
OTHER LIABILITY ARISING FROM THIS LICENSE OR USE OF THE NETFISHING ASSETS.
|
OTHER LIABILITY ARISING FROM THIS LICENSE OR USE OF THE straywild ASSETS.
|
||||||
|
|
||||||
## 10. Additional permission
|
## 10. Additional permission
|
||||||
|
|
||||||
Uses not granted here require written permission from both NETfishing owners.
|
Uses not granted here require written permission from both straywild owners.
|
||||||
A permission granted to one person or project does not amend this license for
|
A permission granted to one person or project does not amend this license for
|
||||||
others.
|
others.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Contribution policy
|
# Contribution policy
|
||||||
|
|
||||||
NETfishing is an owner-directed Woofmeow project and is not accepting
|
straywild is an owner-directed Woofmeow project and is not accepting
|
||||||
unsolicited contributions. Please do not submit pull requests, patches, code,
|
unsolicited contributions. Please do not submit pull requests, patches, code,
|
||||||
artwork, models, audio, writing, documentation, translations, designs, or
|
artwork, models, audio, writing, documentation, translations, designs, or
|
||||||
other implementation work. Pull requests are disabled for the official
|
other implementation work. Pull requests are disabled for the official
|
||||||
|
|
@ -17,7 +17,7 @@ work; it is not a standing invitation to contribute.
|
||||||
|
|
||||||
## Contribution forks
|
## Contribution forks
|
||||||
|
|
||||||
The [NETfishing Asset License](ASSET-LICENSE.md) contains limited permissions
|
The [straywild Asset License](ASSET-LICENSE.md) contains limited permissions
|
||||||
for qualifying Contribution Forks. Those permissions do not promise review or
|
for qualifying Contribution Forks. Those permissions do not promise review or
|
||||||
acceptance and do not override the policy above. Keep the hosting platform's
|
acceptance and do not override the policy above. Keep the hosting platform's
|
||||||
fork relationship visible, preserve all license and attribution notices, and
|
fork relationship visible, preserve all license and attribution notices, and
|
||||||
|
|
@ -79,4 +79,4 @@ using display strings as persistent identifiers.
|
||||||
|
|
||||||
New standalone source files should use `SPDX-License-Identifier:
|
New standalone source files should use `SPDX-License-Identifier:
|
||||||
GPL-3.0-or-later` where the file format permits comments. Do not add that
|
GPL-3.0-or-later` where the file format permits comments. Do not add that
|
||||||
identifier to asset files governed by the NETfishing Asset License.
|
identifier to asset files governed by the straywild Asset License.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# NETfishing contributor terms
|
# straywild contributor terms
|
||||||
|
|
||||||
NETfishing does not accept unsolicited contributions. These terms are retained
|
straywild does not accept unsolicited contributions. These terms are retained
|
||||||
as the governing record for contributions previously accepted after their
|
as the governing record for contributions previously accepted after their
|
||||||
publication and for specific future work that both Owners expressly invite in
|
publication and for specific future work that both Owners expressly invite in
|
||||||
writing before submission. They are not a request or standing invitation for
|
writing before submission. They are not a request or standing invitation for
|
||||||
|
|
@ -9,9 +9,9 @@ patches, pull requests, assets, or other material.
|
||||||
These terms do not retroactively change ownership of earlier work or replace a
|
These terms do not retroactively change ownership of earlier work or replace a
|
||||||
separately signed agreement.
|
separately signed agreement.
|
||||||
|
|
||||||
“Owners” means the two NETfishing co-owners who publish the Project as
|
“Owners” means the two straywild co-owners who publish the Project as
|
||||||
Woofmeow and are publicly credited as Voyager and Endeavour. “Project” means
|
Woofmeow and are publicly credited as Voyager and Endeavour. “Project” means
|
||||||
the official NETfishing game, its servers, tools, documentation, websites,
|
the official straywild game, its servers, tools, documentation, websites,
|
||||||
ports, updates, and promotional materials.
|
ports, updates, and promotional materials.
|
||||||
|
|
||||||
## 1. Your ownership and authority
|
## 1. Your ownership and authority
|
||||||
|
|
@ -56,8 +56,8 @@ royalty-free, transferable, and sublicensable license to:
|
||||||
- license it to Project users under `ASSET-LICENSE.md` or a later Project asset
|
- license it to Project users under `ASSET-LICENSE.md` or a later Project asset
|
||||||
license jointly approved by the Owners.
|
license jointly approved by the Owners.
|
||||||
|
|
||||||
This grant is limited to NETfishing, its promotion, and official successor or
|
This grant is limited to straywild, its promotion, and official successor or
|
||||||
derived NETfishing products. It does not transfer your copyright or authorize
|
derived straywild products. It does not transfer your copyright or authorize
|
||||||
the Owners to sell your contribution as an unrelated standalone asset.
|
the Owners to sell your contribution as an unrelated standalone asset.
|
||||||
|
|
||||||
## 4. Documentation accompanying code
|
## 4. Documentation accompanying code
|
||||||
|
|
@ -78,7 +78,7 @@ or release.
|
||||||
|
|
||||||
## 6. No automatic ownership, employment, or payment
|
## 6. No automatic ownership, employment, or payment
|
||||||
|
|
||||||
Submitting a contribution does not provide ownership of NETfishing, create an
|
Submitting a contribution does not provide ownership of straywild, create an
|
||||||
employment, agency, partnership, or fiduciary relationship, or create a right
|
employment, agency, partnership, or fiduciary relationship, or create a right
|
||||||
to compensation. Any payment, ownership, or employment arrangement requires a
|
to compensation. Any payment, ownership, or employment arrangement requires a
|
||||||
separate written agreement signed by the appropriate parties.
|
separate written agreement signed by the appropriate parties.
|
||||||
|
|
|
||||||
28
README.md
|
|
@ -1,6 +1,6 @@
|
||||||
# NETfishing
|
# straywild
|
||||||
|
|
||||||
NETfishing is a multiplayer-first fishing game built with Godot 4.7. The
|
straywild is a multiplayer-first fishing game built with Godot 4.7. The
|
||||||
current pre-alpha includes host-authoritative fishing and economy flows,
|
current pre-alpha includes host-authoritative fishing and economy flows,
|
||||||
freshwater and saltwater habitats, persistent player data, social features,
|
freshwater and saltwater habitats, persistent player data, social features,
|
||||||
customization, jobs, and a controller-aware interface.
|
customization, jobs, and a controller-aware interface.
|
||||||
|
|
@ -8,39 +8,39 @@ customization, jobs, and a controller-aware interface.
|
||||||
The project is under active development. Interfaces, balance, content, and
|
The project is under active development. Interfaces, balance, content, and
|
||||||
save migrations may continue to change before a stable release.
|
save migrations may continue to change before a stable release.
|
||||||
|
|
||||||
NETfishing is developed and published by **Woofmeow**, the independent team of
|
straywild is developed and published by **Woofmeow**, the independent team of
|
||||||
co-owners publicly credited as Voyager and Endeavour.
|
co-owners publicly credited as Voyager and Endeavour.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
Patreon: https://www.patreon.com/cw/woofmeowgames
|
Patreon: https://www.patreon.com/cw/woofmeowgames
|
||||||
|
|
||||||
Steam: https://store.steampowered.com/app/5068950/NETfishing/
|
Steam: https://store.steampowered.com/app/5068950/straywild/
|
||||||
|
|
||||||
Itch.io: https://sol6-vi.itch.io/netfishing
|
Itch.io: https://sol6-vi.itch.io/straywild
|
||||||
|
|
||||||
Discord: https://discord.gg/5gP22447kc
|
Discord: https://discord.gg/5gP22447kc
|
||||||
|
|
||||||
Matrix: https://matrix.to/#/#netfishing:matrix.makearmy.io
|
Matrix: https://matrix.to/#/#straywild:matrix.makearmy.io
|
||||||
|
|
||||||
Repo: https://forge.makearmy.io/woofmeow/netfishing
|
Repo: https://forge.makearmy.io/woofmeow/straywild
|
||||||
|
|
||||||
Releases: https://forge.makearmy.io/woofmeow/netfishing/releases
|
Releases: https://forge.makearmy.io/woofmeow/straywild/releases
|
||||||
|
|
||||||
|
|
||||||
## Installing release builds
|
## Installing release builds
|
||||||
|
|
||||||
Download and extract the archive for your platform from the official release
|
Download and extract the archive for your platform from the official release
|
||||||
page, then run NETfishing from the extracted platform folder.
|
page, then run straywild from the extracted platform folder.
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
Current macOS builds are not signed or notarized. macOS may block the first
|
Current macOS builds are not signed or notarized. macOS may block the first
|
||||||
launch because it cannot verify the developer. Control-click the NETfishing
|
launch because it cannot verify the developer. Control-click the straywild
|
||||||
application, choose **Open**, then confirm **Open**. If that option is not
|
application, choose **Open**, then confirm **Open**. If that option is not
|
||||||
available, attempt to open the application once, then use **System Settings →
|
available, attempt to open the application once, then use **System Settings →
|
||||||
Privacy & Security → Open Anyway**.
|
Privacy & Security → Open Anyway**.
|
||||||
|
|
||||||
Only bypass this warning for a NETfishing build downloaded from an official
|
Only bypass this warning for a straywild build downloaded from an official
|
||||||
project release.
|
project release.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
@ -110,10 +110,10 @@ world and UI authoring, and testing are consolidated in
|
||||||
- Project-owned software code is licensed under
|
- Project-owned software code is licensed under
|
||||||
[GPL-3.0-or-later](LICENSE).
|
[GPL-3.0-or-later](LICENSE).
|
||||||
- Project-owned artwork, models, music, and other creative assets are covered
|
- Project-owned artwork, models, music, and other creative assets are covered
|
||||||
by the [NETfishing Asset License](ASSET-LICENSE.md). It permits community
|
by the [straywild Asset License](ASSET-LICENSE.md). It permits community
|
||||||
Mods for official NETfishing software and narrowly scoped contribution forks,
|
Mods for official straywild software and narrowly scoped contribution forks,
|
||||||
but not independent forks, clones, or unrelated products.
|
but not independent forks, clones, or unrelated products.
|
||||||
- The NETfishing and Woofmeow names and branding are reserved as described in
|
- The straywild and Woofmeow names and branding are reserved as described in
|
||||||
[TRADEMARKS.md](TRADEMARKS.md).
|
[TRADEMARKS.md](TRADEMARKS.md).
|
||||||
- Third-party materials retain their own terms; see the consolidated
|
- Third-party materials retain their own terms; see the consolidated
|
||||||
[credits, notices, and provenance record](docs/ATTRIBUTION.md).
|
[credits, notices, and provenance record](docs/ATTRIBUTION.md).
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# NETfishing and Woofmeow branding
|
# straywild and Woofmeow branding
|
||||||
|
|
||||||
The NETfishing and Woofmeow names, logos, icons, trade dress, and other source
|
The straywild and Woofmeow names, logos, icons, trade dress, and other source
|
||||||
identifiers are reserved by the NETfishing owners, publishing as Woofmeow.
|
identifiers are reserved by the straywild owners, publishing as Woofmeow.
|
||||||
Their presence in a GPL-licensed repository does not grant trademark rights or
|
Their presence in a GPL-licensed repository does not grant trademark rights or
|
||||||
imply permission to represent another product as official.
|
imply permission to represent another product as official.
|
||||||
|
|
||||||
|
|
@ -10,30 +10,30 @@ exist through use and other law.
|
||||||
|
|
||||||
## Permitted references
|
## Permitted references
|
||||||
|
|
||||||
You may use the names NETfishing and Woofmeow truthfully to:
|
You may use the names straywild and Woofmeow truthfully to:
|
||||||
|
|
||||||
- refer to the official game or development team;
|
- refer to the official game or development team;
|
||||||
- state that software interoperates with or is a Mod for NETfishing;
|
- state that software interoperates with or is a Mod for straywild;
|
||||||
- link to an official repository or distribution page; and
|
- link to an official repository or distribution page; and
|
||||||
- discuss, review, criticize, or report on the Project.
|
- discuss, review, criticize, or report on the Project.
|
||||||
|
|
||||||
Use only the amount of branding reasonably necessary to identify the Project.
|
Use only the amount of branding reasonably necessary to identify the Project.
|
||||||
Do not imply sponsorship, certification, endorsement, or official status.
|
Do not imply sponsorship, certification, endorsement, or official status.
|
||||||
|
|
||||||
An unofficial Mod may use wording such as “Example Mod for NETfishing” if its
|
An unofficial Mod may use wording such as “Example Mod for straywild” if its
|
||||||
name and presentation remain clearly distinct and it displays an unofficial
|
name and presentation remain clearly distinct and it displays an unofficial
|
||||||
notice.
|
notice.
|
||||||
|
|
||||||
## Contribution forks
|
## Contribution forks
|
||||||
|
|
||||||
A qualifying Contribution Fork under `ASSET-LICENSE.md` may retain the
|
A qualifying Contribution Fork under `ASSET-LICENSE.md` may retain the
|
||||||
NETfishing and Woofmeow names, logos, icons, and trade dress already present in
|
straywild and Woofmeow names, logos, icons, and trade dress already present in
|
||||||
the official source repository solely as necessary to reproduce, modify, and
|
the official source repository solely as necessary to reproduce, modify, and
|
||||||
test the Project while preparing a proposed contribution. The source-control
|
test the Project while preparing a proposed contribution. The source-control
|
||||||
host's visible fork relationship or an equivalent repository notice must make
|
host's visible fork relationship or an equivalent repository notice must make
|
||||||
its unofficial contribution purpose clear.
|
its unofficial contribution purpose clear.
|
||||||
|
|
||||||
This permission does not allow a Contribution Fork to use NETfishing or
|
This permission does not allow a Contribution Fork to use straywild or
|
||||||
Woofmeow branding to advertise a public build, release, service, community
|
Woofmeow branding to advertise a public build, release, service, community
|
||||||
edition, or independent product. It does not imply acceptance, sponsorship,
|
edition, or independent product. It does not imply acceptance, sponsorship,
|
||||||
endorsement, or official status.
|
endorsement, or official status.
|
||||||
|
|
@ -44,7 +44,7 @@ The GNU GPL permits forks and redistribution of covered code. A fork or
|
||||||
modified distribution that is not a qualifying Contribution Fork must:
|
modified distribution that is not a qualifying Contribution Fork must:
|
||||||
|
|
||||||
- use a distinct product name;
|
- use a distinct product name;
|
||||||
- remove NETfishing and Woofmeow logos, icons, and official trade dress;
|
- remove straywild and Woofmeow logos, icons, and official trade dress;
|
||||||
- avoid confusingly similar names, domains, package identifiers, and account
|
- avoid confusingly similar names, domains, package identifiers, and account
|
||||||
names; and
|
names; and
|
||||||
- clearly identify itself as independent and unofficial.
|
- clearly identify itself as independent and unofficial.
|
||||||
|
|
@ -53,4 +53,4 @@ These branding terms do not limit rights granted by the GPL to the software
|
||||||
code or lawful nominative, descriptive, comparative, or fair use.
|
code or lawful nominative, descriptive, comparative, or fair use.
|
||||||
|
|
||||||
Permission for broader branding use must be obtained in writing from both
|
Permission for broader branding use must be obtained in writing from both
|
||||||
NETfishing owners.
|
straywild owners.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[plugin]
|
[plugin]
|
||||||
|
|
||||||
name="NETfishing Shoreline Auto-Baker"
|
name="straywild Shoreline Auto-Baker"
|
||||||
description="Rebuilds configured static shoreline ribbons after authored terrain reimports."
|
description="Rebuilds configured static shoreline ribbons after authored terrain reimports."
|
||||||
author="woofmeow"
|
author="woofmeow"
|
||||||
version="1.0.0"
|
version="1.0.0"
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://w7n4gjqq1juc"
|
uid="uid://w7n4gjqq1juc"
|
||||||
path="res://.godot/imported/netfishing_base_character.glb-0167c087f16181d405afb962dc877d2c.scn"
|
path="res://.godot/imported/straywild_base_character.glb-65021653e51a906d3b4a3494f170317f.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/characters/base/netfishing_base_character.glb"
|
source_file="res://art/exported/characters/base/straywild_base_character.glb"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character.glb-0167c087f16181d405afb962dc877d2c.scn"]
|
dest_files=["res://.godot/imported/straywild_base_character.glb-65021653e51a906d3b4a3494f170317f.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://dyjwgkgw0syo8"
|
uid="uid://dyjwgkgw0syo8"
|
||||||
path.s3tc="res://.godot/imported/netfishing_base_character_eyes_simple_shine.png-140bfa3aa0b6f662e8ff9e5721213a61.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_base_character_eyes_simple_shine.png-200a946ddace2078bbe44addb4e4524c.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_base_character_eyes_simple_shine.png-140bfa3aa0b6f662e8ff9e5721213a61.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_base_character_eyes_simple_shine.png-200a946ddace2078bbe44addb4e4524c.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/characters/base/netfishing_base_character_eyes_simple_shine.png"
|
source_file="res://art/exported/characters/base/straywild_base_character_eyes_simple_shine.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character_eyes_simple_shine.png-140bfa3aa0b6f662e8ff9e5721213a61.s3tc.ctex", "res://.godot/imported/netfishing_base_character_eyes_simple_shine.png-140bfa3aa0b6f662e8ff9e5721213a61.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_base_character_eyes_simple_shine.png-200a946ddace2078bbe44addb4e4524c.s3tc.ctex", "res://.godot/imported/straywild_base_character_eyes_simple_shine.png-200a946ddace2078bbe44addb4e4524c.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://dt5gitdtjdvcd"
|
uid="uid://dt5gitdtjdvcd"
|
||||||
path.s3tc="res://.godot/imported/netfishing_base_character_mouth_three.png-90b4a98403d2a291a56a8ed42aaa8473.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_base_character_mouth_three.png-5bcf329b31a11eff496760a63e62d0e2.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_base_character_mouth_three.png-90b4a98403d2a291a56a8ed42aaa8473.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_base_character_mouth_three.png-5bcf329b31a11eff496760a63e62d0e2.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/characters/base/netfishing_base_character_mouth_three.png"
|
source_file="res://art/exported/characters/base/straywild_base_character_mouth_three.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character_mouth_three.png-90b4a98403d2a291a56a8ed42aaa8473.s3tc.ctex", "res://.godot/imported/netfishing_base_character_mouth_three.png-90b4a98403d2a291a56a8ed42aaa8473.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_base_character_mouth_three.png-5bcf329b31a11eff496760a63e62d0e2.s3tc.ctex", "res://.godot/imported/straywild_base_character_mouth_three.png-5bcf329b31a11eff496760a63e62d0e2.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bmho1ryst3smt"
|
uid="uid://bmho1ryst3smt"
|
||||||
path.s3tc="res://.godot/imported/netfishing_base_character_nose_dog_round.png-0008adff5271dd0403e610ef13dd52cf.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_base_character_nose_dog_round.png-e6909a2c139cf4a2748c2b79d1e12d92.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_base_character_nose_dog_round.png-0008adff5271dd0403e610ef13dd52cf.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_base_character_nose_dog_round.png-e6909a2c139cf4a2748c2b79d1e12d92.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/characters/base/netfishing_base_character_nose_dog_round.png"
|
source_file="res://art/exported/characters/base/straywild_base_character_nose_dog_round.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character_nose_dog_round.png-0008adff5271dd0403e610ef13dd52cf.s3tc.ctex", "res://.godot/imported/netfishing_base_character_nose_dog_round.png-0008adff5271dd0403e610ef13dd52cf.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_base_character_nose_dog_round.png-e6909a2c139cf4a2748c2b79d1e12d92.s3tc.ctex", "res://.godot/imported/straywild_base_character_nose_dog_round.png-e6909a2c139cf4a2748c2b79d1e12d92.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
BIN
art/exported/items/equipment/net.glb
Normal file
45
art/exported/items/equipment/net.glb.import
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://dsa6yss1sxfcy"
|
||||||
|
path="res://.godot/imported/net.glb-cbbc53905aec6a50c4a3322ca7a93b1e.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://art/exported/items/equipment/net.glb"
|
||||||
|
dest_files=["res://.godot/imported/net.glb-cbbc53905aec6a50c4a3322ca7a93b1e.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
mesh_library/use_node_names_as_mesh_names=false
|
||||||
|
array_mesh/deduplicate_surfaces=true
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
|
gltf/texture_map_mode=1
|
||||||
BIN
art/exported/items/equipment/net_Material.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
45
art/exported/items/equipment/net_Material.png.import
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://binoqhg45vgbs"
|
||||||
|
path.s3tc="res://.godot/imported/net_Material.png-f4c4b0400561bc2751fe719b6b1a1e1a.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/net_Material.png-f4c4b0400561bc2751fe719b6b1a1e1a.etc2.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "ef2c2ae657c9460c90eb808ba5217f39"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://art/exported/items/equipment/net_Material.png"
|
||||||
|
dest_files=["res://.godot/imported/net_Material.png-f4c4b0400561bc2751fe719b6b1a1e1a.s3tc.ctex", "res://.godot/imported/net_Material.png-f4c4b0400561bc2751fe719b6b1a1e1a.etc2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
BIN
art/exported/items/equipment/net_Plane Base Color.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
45
art/exported/items/equipment/net_Plane Base Color.png.import
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cdsabucjy5rpk"
|
||||||
|
path.s3tc="res://.godot/imported/net_Plane Base Color.png-3875ae3dd186ddf319c55aabb13e663f.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/net_Plane Base Color.png-3875ae3dd186ddf319c55aabb13e663f.etc2.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "a6001c381d4c8e16bd2d64ea74ccff82"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://art/exported/items/equipment/net_Plane Base Color.png"
|
||||||
|
dest_files=["res://.godot/imported/net_Plane Base Color.png-3875ae3dd186ddf319c55aabb13e663f.s3tc.ctex", "res://.godot/imported/net_Plane Base Color.png-3875ae3dd186ddf319c55aabb13e663f.etc2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
|
Before Width: | Height: | Size: 362 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 47 KiB |
BIN
art/exported/system_icons/straywild.ico
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
art/exported/system_icons/straywild_1024.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bkh5hw8wwu8pc"
|
uid="uid://bkh5hw8wwu8pc"
|
||||||
path="res://.godot/imported/netfishing_1024.png-7c53a099ed2743b4a623c258641b1d29.ctex"
|
path="res://.godot/imported/straywild_1024.png-b9b5c159c9fcecc21b04324370d4522f.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/system_icons/netfishing_1024.png"
|
source_file="res://art/exported/system_icons/straywild_1024.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_1024.png-7c53a099ed2743b4a623c258641b1d29.ctex"]
|
dest_files=["res://.godot/imported/straywild_1024.png-b9b5c159c9fcecc21b04324370d4522f.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
BIN
art/exported/system_icons/straywild_256.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
|
@ -3,15 +3,15 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://cty16m8ydla06"
|
uid="uid://cty16m8ydla06"
|
||||||
path="res://.godot/imported/netfishing_256.png-d9dfc9c7871ac38bc73d09d00df679be.ctex"
|
path="res://.godot/imported/straywild_256.png-87b7e62e710eae4d3e3ed24a8454ca6d.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/system_icons/netfishing_256.png"
|
source_file="res://art/exported/system_icons/straywild_256.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_256.png-d9dfc9c7871ac38bc73d09d00df679be.ctex"]
|
dest_files=["res://.godot/imported/straywild_256.png-87b7e62e710eae4d3e3ed24a8454ca6d.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://cb4bcakhoprm8"
|
uid="uid://cb4bcakhoprm8"
|
||||||
path="res://.godot/imported/netfishing_base_character.blend-65bf3bc5b77cc1a37fa3f81ebd808d37.scn"
|
path="res://.godot/imported/straywild_base_character.blend-02abbfdb9b1d393f1bd3cfface615e27.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_base_character.blend"
|
source_file="res://art/source/characters/base/straywild_base_character.blend"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character.blend-65bf3bc5b77cc1a37fa3f81ebd808d37.scn"]
|
dest_files=["res://.godot/imported/straywild_base_character.blend-02abbfdb9b1d393f1bd3cfface615e27.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://bfhnup14638r7"
|
uid="uid://bfhnup14638r7"
|
||||||
path="res://.godot/imported/netfishing_base_character.glb-cbdc33eaa4fcd1d2d2a8f4a463b228d6.scn"
|
path="res://.godot/imported/straywild_base_character.glb-c9650c715a1b5b9ae0d8541191f7d7a9.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_base_character.glb"
|
source_file="res://art/source/characters/base/straywild_base_character.glb"
|
||||||
dest_files=["res://.godot/imported/netfishing_base_character.glb-cbdc33eaa4fcd1d2d2a8f4a463b228d6.scn"]
|
dest_files=["res://.godot/imported/straywild_base_character.glb-c9650c715a1b5b9ae0d8541191f7d7a9.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://d38y8blk2w5c5"
|
uid="uid://d38y8blk2w5c5"
|
||||||
path="res://.godot/imported/netfishing_character_source.blend-1d18c95606937d4c8bcb87e334e02ee5.scn"
|
path="res://.godot/imported/straywild_character_source.blend-0e7b8a87008f88e309ad73a63561ef5b.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source.blend"
|
source_file="res://art/source/characters/base/straywild_character_source.blend"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source.blend-1d18c95606937d4c8bcb87e334e02ee5.scn"]
|
dest_files=["res://.godot/imported/straywild_character_source.blend-0e7b8a87008f88e309ad73a63561ef5b.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://3uq4cxiomttt"
|
uid="uid://3uq4cxiomttt"
|
||||||
path="res://.godot/imported/netfishing_character_source.glb-9c98ee44b142c5b3d06f0838b7d2c9c4.scn"
|
path="res://.godot/imported/straywild_character_source.glb-3a8ccc55dbe60da1b70b62110b206353.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source.glb"
|
source_file="res://art/source/characters/base/straywild_character_source.glb"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source.glb-9c98ee44b142c5b3d06f0838b7d2c9c4.scn"]
|
dest_files=["res://.godot/imported/straywild_character_source.glb-3a8ccc55dbe60da1b70b62110b206353.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bdomsntfeovnc"
|
uid="uid://bdomsntfeovnc"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_eyes1_eyebrows1.png-a0b9f287e407afd9688e141dc5f2b801.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_eyes1_eyebrows1.png-3c638377e631a94b998336d0ca1d8b8e.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_eyes1_eyebrows1.png-a0b9f287e407afd9688e141dc5f2b801.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_eyes1_eyebrows1.png-3c638377e631a94b998336d0ca1d8b8e.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_eyes1_eyebrows1.png"
|
source_file="res://art/source/characters/base/straywild_character_source_eyes1_eyebrows1.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_eyes1_eyebrows1.png-a0b9f287e407afd9688e141dc5f2b801.s3tc.ctex", "res://.godot/imported/netfishing_character_source_eyes1_eyebrows1.png-a0b9f287e407afd9688e141dc5f2b801.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_eyes1_eyebrows1.png-3c638377e631a94b998336d0ca1d8b8e.s3tc.ctex", "res://.godot/imported/straywild_character_source_eyes1_eyebrows1.png-3c638377e631a94b998336d0ca1d8b8e.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://du4u6meapay05"
|
uid="uid://du4u6meapay05"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_eyes_simple_shine.png-965743f3716320bbc385096956ffef2d.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_eyes_simple_shine.png-97500ad873e0da3aaf0e9e3c3198e38a.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_eyes_simple_shine.png-965743f3716320bbc385096956ffef2d.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_eyes_simple_shine.png-97500ad873e0da3aaf0e9e3c3198e38a.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_eyes_simple_shine.png"
|
source_file="res://art/source/characters/base/straywild_character_source_eyes_simple_shine.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_eyes_simple_shine.png-965743f3716320bbc385096956ffef2d.s3tc.ctex", "res://.godot/imported/netfishing_character_source_eyes_simple_shine.png-965743f3716320bbc385096956ffef2d.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_eyes_simple_shine.png-97500ad873e0da3aaf0e9e3c3198e38a.s3tc.ctex", "res://.godot/imported/straywild_character_source_eyes_simple_shine.png-97500ad873e0da3aaf0e9e3c3198e38a.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://css0k0virgoph"
|
uid="uid://css0k0virgoph"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_mouth1.png-b323b9153acd3f552f35c1d1108567c8.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_mouth1.png-ff2ed280ca7e84bdd0749ed5b5b16f54.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_mouth1.png-b323b9153acd3f552f35c1d1108567c8.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_mouth1.png-ff2ed280ca7e84bdd0749ed5b5b16f54.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_mouth1.png"
|
source_file="res://art/source/characters/base/straywild_character_source_mouth1.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_mouth1.png-b323b9153acd3f552f35c1d1108567c8.s3tc.ctex", "res://.godot/imported/netfishing_character_source_mouth1.png-b323b9153acd3f552f35c1d1108567c8.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_mouth1.png-ff2ed280ca7e84bdd0749ed5b5b16f54.s3tc.ctex", "res://.godot/imported/straywild_character_source_mouth1.png-ff2ed280ca7e84bdd0749ed5b5b16f54.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://di20c1x8vksi1"
|
uid="uid://di20c1x8vksi1"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_mouth_three.png-6bf79d4c9c660d30fb7fc365f0039313.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_mouth_three.png-adf40ee30e725bafadf6a8fa4dbd8abf.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_mouth_three.png-6bf79d4c9c660d30fb7fc365f0039313.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_mouth_three.png-adf40ee30e725bafadf6a8fa4dbd8abf.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_mouth_three.png"
|
source_file="res://art/source/characters/base/straywild_character_source_mouth_three.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_mouth_three.png-6bf79d4c9c660d30fb7fc365f0039313.s3tc.ctex", "res://.godot/imported/netfishing_character_source_mouth_three.png-6bf79d4c9c660d30fb7fc365f0039313.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_mouth_three.png-adf40ee30e725bafadf6a8fa4dbd8abf.s3tc.ctex", "res://.godot/imported/straywild_character_source_mouth_three.png-adf40ee30e725bafadf6a8fa4dbd8abf.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://7dwa0bfev1rk"
|
uid="uid://7dwa0bfev1rk"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_nose1.2.png-ef4dd456c5b0f0db73b3dc063bfba941.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_nose1.2.png-0a8355472731651768eaa5fc2ee168d4.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_nose1.2.png-ef4dd456c5b0f0db73b3dc063bfba941.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_nose1.2.png-0a8355472731651768eaa5fc2ee168d4.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_nose1.2.png"
|
source_file="res://art/source/characters/base/straywild_character_source_nose1.2.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_nose1.2.png-ef4dd456c5b0f0db73b3dc063bfba941.s3tc.ctex", "res://.godot/imported/netfishing_character_source_nose1.2.png-ef4dd456c5b0f0db73b3dc063bfba941.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_nose1.2.png-0a8355472731651768eaa5fc2ee168d4.s3tc.ctex", "res://.godot/imported/straywild_character_source_nose1.2.png-0a8355472731651768eaa5fc2ee168d4.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
|
|
@ -3,8 +3,8 @@
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://b0p55hwdry2cr"
|
uid="uid://b0p55hwdry2cr"
|
||||||
path.s3tc="res://.godot/imported/netfishing_character_source_nose_dog_round.png-1c89150861ebff3f930698c1747a0369.s3tc.ctex"
|
path.s3tc="res://.godot/imported/straywild_character_source_nose_dog_round.png-d1ea0db61e41dfeeed3b599286ffb82c.s3tc.ctex"
|
||||||
path.etc2="res://.godot/imported/netfishing_character_source_nose_dog_round.png-1c89150861ebff3f930698c1747a0369.etc2.ctex"
|
path.etc2="res://.godot/imported/straywild_character_source_nose_dog_round.png-d1ea0db61e41dfeeed3b599286ffb82c.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
|
|
@ -15,8 +15,8 @@ generator_parameters={
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/source/characters/base/netfishing_character_source_nose_dog_round.png"
|
source_file="res://art/source/characters/base/straywild_character_source_nose_dog_round.png"
|
||||||
dest_files=["res://.godot/imported/netfishing_character_source_nose_dog_round.png-1c89150861ebff3f930698c1747a0369.s3tc.ctex", "res://.godot/imported/netfishing_character_source_nose_dog_round.png-1c89150861ebff3f930698c1747a0369.etc2.ctex"]
|
dest_files=["res://.godot/imported/straywild_character_source_nose_dog_round.png-d1ea0db61e41dfeeed3b599286ffb82c.s3tc.ctex", "res://.godot/imported/straywild_character_source_nose_dog_round.png-d1ea0db61e41dfeeed3b599286ffb82c.etc2.ctex"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
BIN
art/source/items/equipment/net.blend
Normal file
|
|
@ -7,7 +7,7 @@ prove authorship or licensing.
|
||||||
|
|
||||||
## Ownership and credits
|
## Ownership and credits
|
||||||
|
|
||||||
NETfishing is jointly owned, developed, and published by its creators,
|
straywild is jointly owned, developed, and published by its creators,
|
||||||
publicly credited as Voyager and Endeavour and operating collectively as the
|
publicly credited as Voyager and Endeavour and operating collectively as the
|
||||||
independent team Woofmeow.
|
independent team Woofmeow.
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ independent team Woofmeow.
|
||||||
|
|
||||||
Voyager is also the original catalog porter credit in PortMaster metadata.
|
Voyager is also the original catalog porter credit in PortMaster metadata.
|
||||||
Third-party creators are credited with their individual records below. Those
|
Third-party creators are credited with their individual records below. Those
|
||||||
credits do not imply endorsement of NETfishing, Woofmeow, or its owners.
|
credits do not imply endorsement of straywild, Woofmeow, or its owners.
|
||||||
|
|
||||||
## License map
|
## License map
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ Do not describe the complete repository as covered only by the GPL.
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Project-owned software code, shaders, code-oriented scene/resource configuration, tests, build tooling, and server software | GPL-3.0-or-later; source-root `LICENSE` and packaged `GPL-3.0-or-later.txt` |
|
| Project-owned software code, shaders, code-oriented scene/resource configuration, tests, build tooling, and server software | GPL-3.0-or-later; source-root `LICENSE` and packaged `GPL-3.0-or-later.txt` |
|
||||||
| Project-owned artwork, textures, models, animation, music, audio, narrative content, characters, and other creative assets | Source-root or packaged `ASSET-LICENSE.md` |
|
| Project-owned artwork, textures, models, animation, music, audio, narrative content, characters, and other creative assets | Source-root or packaged `ASSET-LICENSE.md` |
|
||||||
| NETfishing and Woofmeow names, logos, icons, and official identity | Source-root or packaged `TRADEMARKS.md` |
|
| straywild and Woofmeow names, logos, icons, and official identity | Source-root or packaged `TRADEMARKS.md` |
|
||||||
| Third-party engines, fonts, sounds, and other external material | Their original terms, recorded below and in adjacent license texts where applicable |
|
| Third-party engines, fonts, sounds, and other external material | Their original terms, recorded below and in adjacent license texts where applicable |
|
||||||
| Previously accepted or expressly invited outside contributions | Source-root `CONTRIBUTOR-TERMS.md` plus any separately signed agreement |
|
| Previously accepted or expressly invited outside contributions | Source-root `CONTRIBUTOR-TERMS.md` plus any separately signed agreement |
|
||||||
|
|
||||||
|
|
@ -50,22 +50,22 @@ the terms of their source material or generating code. Repository location
|
||||||
alone does not relicense third-party material.
|
alone does not relicense third-party material.
|
||||||
|
|
||||||
The GPL permits study, modification, redistribution, and forks of covered
|
The GPL permits study, modification, redistribution, and forks of covered
|
||||||
code. It does not grant rights to NETfishing creative assets or branding. The
|
code. It does not grant rights to straywild creative assets or branding. The
|
||||||
NETfishing Asset License separately permits qualifying noncommercial add-on
|
straywild Asset License separately permits qualifying noncommercial add-on
|
||||||
Mods for official NETfishing software and narrowly scoped Contribution Forks
|
Mods for official straywild software and narrowly scoped Contribution Forks
|
||||||
used to prepare changes for possible upstream inclusion. It does not permit
|
used to prepare changes for possible upstream inclusion. It does not permit
|
||||||
those assets to accompany independent code forks, clones, standalone games,
|
those assets to accompany independent code forks, clones, standalone games,
|
||||||
unrelated products, or general-purpose asset packs. A GPL fork that is not a
|
unrelated products, or general-purpose asset packs. A GPL fork that is not a
|
||||||
qualifying Contribution Fork must replace NETfishing assets and reserved
|
qualifying Contribution Fork must replace straywild assets and reserved
|
||||||
branding with independently licensed material and a distinct identity.
|
branding with independently licensed material and a distinct identity.
|
||||||
|
|
||||||
Project-wide code, asset, branding, or contributor-license changes require
|
Project-wide code, asset, branding, or contributor-license changes require
|
||||||
written approval from both NETfishing owners under their private joint
|
written approval from both straywild owners under their private joint
|
||||||
ownership agreement.
|
ownership agreement.
|
||||||
|
|
||||||
## Godot Engine notice
|
## Godot Engine notice
|
||||||
|
|
||||||
NETfishing uses Godot Engine under the MIT License:
|
straywild uses Godot Engine under the MIT License:
|
||||||
|
|
||||||
> Copyright (c) 2014-present Godot Engine contributors.
|
> Copyright (c) 2014-present Godot Engine contributors.
|
||||||
> Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
|
> Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
|
||||||
|
|
@ -103,7 +103,7 @@ FreeType for font rendering; portions are copyright The FreeType Project
|
||||||
Runtime file: `ui/fonts/seattle_avenue.otf`; source, hash, and original notice:
|
Runtime file: `ui/fonts/seattle_avenue.otf`; source, hash, and original notice:
|
||||||
`ui/fonts/Seattle-Avenue-LICENSE.txt`.
|
`ui/fonts/Seattle-Avenue-LICENSE.txt`.
|
||||||
|
|
||||||
Public-domain fonts are not governed by the NETfishing Asset License.
|
Public-domain fonts are not governed by the straywild Asset License.
|
||||||
|
|
||||||
## Intake policy
|
## Intake policy
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ owners' private project records. This public document should contain the
|
||||||
credits and license notices needed by recipients; it should not duplicate a
|
credits and license notices needed by recipients; it should not duplicate a
|
||||||
changing file inventory that can be derived from the repository itself.
|
changing file inventory that can be derived from the repository itself.
|
||||||
|
|
||||||
NETfishing does not accept unsolicited contributions. For work expressly
|
straywild does not accept unsolicited contributions. For work expressly
|
||||||
invited by both Owners, maintainers must obtain affirmative agreement to the
|
invited by both Owners, maintainers must obtain affirmative agreement to the
|
||||||
source-root `CONTRIBUTOR-TERMS.md` and retain the written invitation and
|
source-root `CONTRIBUTOR-TERMS.md` and retain the written invitation and
|
||||||
agreement in a durable Project record.
|
agreement in a durable Project record.
|
||||||
|
|
@ -159,8 +159,8 @@ against the repository when this record was revised.
|
||||||
|
|
||||||
| Material | Runtime location | Credit or terms |
|
| Material | Runtime location | Credit or terms |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Kat animalese alphabet and number sounds | `sound/dialogue/animalese/alphanumeric/` | Project-processed derivatives of the original source voice recording supplied by NETfishing community member kat. |
|
| Kat animalese alphabet and number sounds | `sound/dialogue/animalese/alphanumeric/` | Project-processed derivatives of the original source voice recording supplied by straywild community member kat. |
|
||||||
| Kim animalese alphabet and number sounds | `sound/dialogue/animalese/kim/` | Project-processed derivatives of the original source voice recording supplied by NETfishing community member kim. |
|
| Kim animalese alphabet and number sounds | `sound/dialogue/animalese/kim/` | Project-processed derivatives of the original source voice recording supplied by straywild community member kim. |
|
||||||
| Tuffy font | `ui/fonts/Tuffy_Bold.otf` | Public-domain dedication in `ui/fonts/Tuffy-LICENSE.txt`. |
|
| Tuffy font | `ui/fonts/Tuffy_Bold.otf` | Public-domain dedication in `ui/fonts/Tuffy-LICENSE.txt`. |
|
||||||
| Seattle Avenue font | `ui/fonts/seattle_avenue.otf` | Public-domain font by JLH Fonts; notice in `ui/fonts/Seattle-Avenue-LICENSE.txt`. |
|
| Seattle Avenue font | `ui/fonts/seattle_avenue.otf` | Public-domain font by JLH Fonts; notice in `ui/fonts/Seattle-Avenue-LICENSE.txt`. |
|
||||||
| Fishing fight loop | `audio/sfx/fishing/fighting.wav` | Edited from “Spinning reel.wav” by Freesound user tosha73, sound 509902, CC0. |
|
| Fishing fight loop | `audio/sfx/fishing/fighting.wav` | Edited from “Spinning reel.wav” by Freesound user tosha73, sound 509902, CC0. |
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Development reference
|
# Development reference
|
||||||
|
|
||||||
This is the authoritative reference for NETfishing architecture, engineering
|
This is the authoritative reference for straywild architecture, engineering
|
||||||
decisions, content policy, authoring, and validation.
|
decisions, content policy, authoring, and validation.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
@ -43,7 +43,7 @@ open host may publish a short-lived room lease, and the shared Join Game page
|
||||||
may browse compatible leases before handing the selected address back to the
|
may browse compatible leases before handing the selected address back to the
|
||||||
existing direct ENet connection flow. The directory does not carry gameplay
|
existing direct ENet connection flow. The directory does not carry gameplay
|
||||||
traffic or become a gameplay authority. Its base URL comes from
|
traffic or become a gameplay authority. Its base URL comes from
|
||||||
`network/discovery/base_url`, with `NETFISHING_DISCOVERY_URL` available as a
|
`network/discovery/base_url`, with `straywild_DISCOVERY_URL` available as a
|
||||||
development/deployment override.
|
development/deployment override.
|
||||||
|
|
||||||
Friendships are local identity relationships shared across save slots. A live,
|
Friendships are local identity relationships shared across save slots. A live,
|
||||||
|
|
@ -261,7 +261,7 @@ copies of the entire customization catalog.
|
||||||
|
|
||||||
### Texture sampling
|
### Texture sampling
|
||||||
|
|
||||||
NETfishing artwork uses nearest-neighbor sampling. Do not enable linear,
|
straywild artwork uses nearest-neighbor sampling. Do not enable linear,
|
||||||
bilinear, trilinear, or anisotropic texture filtering. Shader samplers must
|
bilinear, trilinear, or anisotropic texture filtering. Shader samplers must
|
||||||
declare `filter_nearest`. The three canonical repeating terrain textures are
|
declare `filter_nearest`. The three canonical repeating terrain textures are
|
||||||
the sole mipmap exception: their projected shader uses nearest-filtered
|
the sole mipmap exception: their projected shader uses nearest-filtered
|
||||||
|
|
@ -351,10 +351,10 @@ godot --headless --path . --script tests/fish_catalog_content_validation.gd
|
||||||
rm -rf -- "$test_root"
|
rm -rf -- "$test_root"
|
||||||
```
|
```
|
||||||
|
|
||||||
Do not point `NETFISHING_DATA_DIR` at an arbitrary empty directory; it is an
|
Do not point `straywild_DATA_DIR` at an arbitrary empty directory; it is an
|
||||||
explicit portable-data override and must identify a valid data root. The
|
explicit portable-data override and must identify a valid data root. The
|
||||||
PortMaster launcher is the narrow exception: it also sets
|
PortMaster launcher is the narrow exception: it also sets
|
||||||
`NETFISHING_CREATE_DATA_DIR=1`, allowing the game to initialize its known empty
|
`straywild_CREATE_DATA_DIR=1`, allowing the game to initialize its known empty
|
||||||
external save directory on first launch.
|
external save directory on first launch.
|
||||||
|
|
||||||
Headless tests cannot prove visual alignment, mouse routing, shader appearance,
|
Headless tests cannot prove visual alignment, mouse routing, shader appearance,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
# PortMaster reference
|
# PortMaster reference
|
||||||
|
|
||||||
NETfishing's PortMaster release is a canonical PortMaster package, not a
|
straywild's PortMaster release is a canonical PortMaster package, not a
|
||||||
version-named generic ZIP. The installer-facing archive must be named
|
version-named generic ZIP. The installer-facing archive must be named
|
||||||
`netfishing.zip`, and its root must contain exactly:
|
`straywild.zip`, and its root must contain exactly:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
NETfishing.sh
|
straywild.sh
|
||||||
netfishing/
|
straywild/
|
||||||
```
|
```
|
||||||
|
|
||||||
`port.json` belongs at `netfishing/port.json` in the distributable archive.
|
`port.json` belongs at `straywild/port.json` in the distributable archive.
|
||||||
The upstream source-submission layout keeps it beside the launcher and port
|
The upstream source-submission layout keeps it beside the launcher and port
|
||||||
directory, but PortMaster's release builder relocates it into the declared
|
directory, but PortMaster's release builder relocates it into the declared
|
||||||
port directory. Do not copy the source-submission layout directly into a
|
port directory. Do not copy the source-submission layout directly into a
|
||||||
|
|
@ -17,7 +17,7 @@ release ZIP.
|
||||||
|
|
||||||
HarbourMaster's installer also relocates recognized non-script files found at
|
HarbourMaster's installer also relocates recognized non-script files found at
|
||||||
an archive root into the detected port directory. That compatibility behavior
|
an archive root into the detected port directory. That compatibility behavior
|
||||||
masked NETfishing's former root-level `port.json` during auto-install tests.
|
masked straywild's former root-level `port.json` during auto-install tests.
|
||||||
Directly extracting the same archive into `/ports` did not perform the repair.
|
Directly extracting the same archive into `/ports` did not perform the repair.
|
||||||
Do not rely on installer relocation; build the distributable layout correctly.
|
Do not rely on installer relocation; build the distributable layout correctly.
|
||||||
|
|
||||||
|
|
@ -26,30 +26,34 @@ directory. The templates in `scripts/portmaster/` are authoritative.
|
||||||
|
|
||||||
## Release contract
|
## Release contract
|
||||||
|
|
||||||
- `port.json` uses schema version 4, names `netfishing.zip`, and marks the
|
- `port.json` uses schema version 4, names `straywild.zip`, and marks the
|
||||||
self-contained package ready to run.
|
self-contained package ready to run.
|
||||||
- `NETfishing.sh` does not contain a `# PORTMASTER:` signature in the source or
|
- `straywild.sh` does not contain a `# PORTMASTER:` signature in the source or
|
||||||
distributable archive. HarbourMaster adds that installation marker when it
|
distributable archive. HarbourMaster adds that installation marker when it
|
||||||
installs the port.
|
installs the port.
|
||||||
- The executable is `netfishing/NETfishing.aarch64`.
|
- The executable is `straywild/straywild.aarch64`.
|
||||||
- The package declares AArch64, two analog sticks, GLIBC 2.28, and
|
- The package declares AArch64, two analog sticks, GLIBC 2.28, and
|
||||||
`weston_pkg_0.2.squashfs`.
|
`weston_pkg_0.2.squashfs`.
|
||||||
- The launcher starts GPTOKEYB with the explicit `netfishing.gptk` no-op map.
|
- The launcher starts GPTOKEYB with the explicit `straywild.gptk` no-op map.
|
||||||
Every keyboard and mouse binding is disabled, leaving only GPTOKEYB's
|
Every keyboard and mouse binding is disabled, leaving only GPTOKEYB's
|
||||||
device-specific force-quit chord while Godot and NETfishing's controller
|
device-specific force-quit chord while Godot and straywild's controller
|
||||||
mapping manager handle gameplay input. The explicit map also avoids the
|
mapping manager handle gameplay input. The explicit map also avoids the
|
||||||
anomalous controller behavior observed on ROCKNIX without a passthrough map.
|
anomalous controller behavior observed on ROCKNIX without a passthrough map.
|
||||||
- The launcher calls `pm_platform_helper` for the game executable after
|
- The launcher calls `pm_platform_helper` for the game executable after
|
||||||
starting GPTOKEYB and calls `pm_finish` after the game exits.
|
starting GPTOKEYB and calls `pm_finish` after the game exits.
|
||||||
- NETfishing automatically creates player data for new installations under
|
- straywild automatically creates player data for new installations under
|
||||||
`ports/saves/netfishing/` and does not present the in-game folder picker.
|
`ports/saves/straywild/` and does not present the in-game folder picker.
|
||||||
- Existing installations with a selected data root keep that location when
|
- Existing installations with a selected data root keep that location when
|
||||||
upgraded. Device-local data, configuration, and cache remain under
|
upgraded. Device-local data, configuration, and cache remain under
|
||||||
`netfishing/conf/data`, `netfishing/conf/config`, and
|
`straywild/conf/data`, `straywild/conf/config`, and
|
||||||
`netfishing/conf/cache`.
|
`straywild/conf/cache`.
|
||||||
|
- A rebrand upgrade copies an existing `netfishing/conf/` tree into the new
|
||||||
|
`straywild/conf/` tree when the latter does not exist. It also reuses an
|
||||||
|
existing `ports/saves/netfishing/` data root rather than creating an empty
|
||||||
|
replacement. New installations use straywild paths exclusively.
|
||||||
- The archive must not contain `conf/`, saves, identities, logs, source files,
|
- The archive must not contain `conf/`, saves, identities, logs, source files,
|
||||||
`.git`, or `.godot` content.
|
`.git`, or `.godot` content.
|
||||||
- Release downloads must publish only the canonical `netfishing.zip` for this
|
- Release downloads must publish only the canonical `straywild.zip` for this
|
||||||
platform. Do not also publish a byte-identical versioned PortMaster ZIP;
|
platform. Do not also publish a byte-identical versioned PortMaster ZIP;
|
||||||
HarbourMaster identifies the port by its canonical archive name and the
|
HarbourMaster identifies the port by its canonical archive name and the
|
||||||
Forgejo release tag already supplies the version.
|
Forgejo release tag already supplies the version.
|
||||||
|
|
@ -67,7 +71,7 @@ The script deletes and regenerates the Linux ARM64 export, stages the package,
|
||||||
validates its structure, and writes:
|
validates its structure, and writes:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
builds/v<project-version>/netfishing.zip
|
builds/v<project-version>/straywild.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
`--package-only` is reserved for repackaging an already validated ARM64 export.
|
`--package-only` is reserved for repackaging an already validated ARM64 export.
|
||||||
|
|
@ -83,7 +87,7 @@ bash scripts/build_portmaster.sh --package-only --hotfix
|
||||||
|
|
||||||
The hotfix keeps the game executable and PCK tied to the release tag while
|
The hotfix keeps the game executable and PCK tied to the release tag while
|
||||||
recording the newer packaging commit separately in `BUILD-INFO.txt`. Replace
|
recording the newer packaging commit separately in `BUILD-INFO.txt`. Replace
|
||||||
the release's existing `netfishing.zip`; never move the game release tag.
|
the release's existing `straywild.zip`; never move the game release tag.
|
||||||
|
|
||||||
## Local muOS installation
|
## Local muOS installation
|
||||||
|
|
||||||
|
|
@ -93,22 +97,22 @@ The muOS auto-install directory is:
|
||||||
/mnt/mmc/MUOS/PortMaster/autoinstall/
|
/mnt/mmc/MUOS/PortMaster/autoinstall/
|
||||||
```
|
```
|
||||||
|
|
||||||
For an explicit offline installation test, copy `netfishing.zip` to a temporary
|
For an explicit offline installation test, copy `straywild.zip` to a temporary
|
||||||
device directory and run:
|
device directory and run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/mnt/mmc/MUOS/PortMaster/harbourmaster \
|
/mnt/mmc/MUOS/PortMaster/harbourmaster \
|
||||||
--offline --no-check install ./netfishing.zip
|
--offline --no-check install ./straywild.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
Before upgrading an existing installation, preserve
|
Before upgrading an existing installation, preserve either the current
|
||||||
`/mnt/mmc/ports/netfishing/conf/` and `/mnt/mmc/ports/saves/netfishing/` on the
|
`/mnt/mmc/ports/straywild/` paths or the former `/mnt/mmc/ports/netfishing/`
|
||||||
device. After installation:
|
paths on the device. After installation:
|
||||||
|
|
||||||
1. Confirm the installed executable and PCK hashes match the staged release.
|
1. Confirm the installed executable and PCK hashes match the staged release.
|
||||||
2. Confirm HarbourMaster added its `# PORTMASTER:` installation signature to
|
2. Confirm HarbourMaster added its `# PORTMASTER:` installation signature to
|
||||||
the installed launcher, then confirm the launcher starts GPTOKEYB with
|
the installed launcher, then confirm the launcher starts GPTOKEYB with
|
||||||
`netfishing.gptk` and calls `pm_platform_helper` for the game executable.
|
`straywild.gptk` and calls `pm_platform_helper` for the game executable.
|
||||||
3. Confirm `conf/` and the external save directory were not replaced or
|
3. Confirm `conf/` and the external save directory were not replaced or
|
||||||
removed.
|
removed.
|
||||||
4. Launch the installed port through the normal muOS menu.
|
4. Launch the installed port through the normal muOS menu.
|
||||||
|
|
@ -117,7 +121,7 @@ device. After installation:
|
||||||
Start+Select on most devices.
|
Start+Select on most devices.
|
||||||
|
|
||||||
Installing the public PortMaster catalog entry can still install an older
|
Installing the public PortMaster catalog entry can still install an older
|
||||||
catalog build until the upstream `netfishing.zip` is updated. A local release
|
catalog build until the upstream `straywild.zip` is updated. A local release
|
||||||
test must install the generated local archive explicitly.
|
test must install the generated local archive explicitly.
|
||||||
|
|
||||||
## Template provenance
|
## Template provenance
|
||||||
|
|
@ -130,7 +134,7 @@ f24daae48f543b3a270a5aa46b5e73a31904bf0c7216d4c8a9e15a8dc48a5eed screenshot.png
|
||||||
```
|
```
|
||||||
|
|
||||||
The remaining catalog metadata assets were copied from the installed official
|
The remaining catalog metadata assets were copied from the installed official
|
||||||
`netfishing.zip` package and are intentionally preserved byte-for-byte:
|
`straywild.zip` package and are intentionally preserved byte-for-byte:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
e2a9d132744684c67865c01eca027a8c9946b4c5a19da57c82f1af0373dc83b7 gameinfo.xml
|
e2a9d132744684c67865c01eca027a8c9946b4c5a19da57c82f1af0373dc83b7 gameinfo.xml
|
||||||
|
|
@ -160,7 +164,7 @@ The device-verified Godot mapping is:
|
||||||
- left-stick click `b9`, left trigger `b10`, right trigger `b11`, right-stick click `b12`
|
- left-stick click `b9`, left trigger `b10`, right trigger `b11`, right-stick click `b12`
|
||||||
- D-pad `h0`; left and right sticks `a0..a3`
|
- D-pad `h0`; left and right sticks `a0..a3`
|
||||||
|
|
||||||
`scripts/portmaster/NETfishing.sh` must replace the incompatible SDL2 entry
|
`scripts/portmaster/straywild.sh` must replace the incompatible SDL2 entry
|
||||||
with the Godot entry when that SDL2 GUID is selected. Do not append the two
|
with the Godot entry when that SDL2 GUID is selected. Do not append the two
|
||||||
entries with a newline. WestonPack reconstructs the wrapped game command
|
entries with a newline. WestonPack reconstructs the wrapped game command
|
||||||
through a shell, so raw mapping values passed in that command can be split into
|
through a shell, so raw mapping values passed in that command can be split into
|
||||||
|
|
@ -169,14 +173,14 @@ this failure with the `GO-Super Gamepad` mapping. The outer Weston environment
|
||||||
also does not reliably preserve the corrected muOS mapping for the game.
|
also does not reliably preserve the corrected muOS mapping for the game.
|
||||||
|
|
||||||
Write the exact selected mapping to `conf/cache/controller_mapping.txt` before
|
Write the exact selected mapping to `conf/cache/controller_mapping.txt` before
|
||||||
starting Weston. Weston must launch `launch-netfishing.sh`, which reads that
|
starting Weston. Weston must launch `launch-straywild.sh`, which reads that
|
||||||
file, exports `SDL_GAMECONTROLLERCONFIG`, and immediately replaces itself with
|
file, exports `SDL_GAMECONTROLLERCONFIG`, and immediately replaces itself with
|
||||||
the game process. This applies the mapping at the same point as the working
|
the game process. This applies the mapping at the same point as the working
|
||||||
0.10.1 launcher without passing its raw text through WestonPack's command
|
0.10.1 launcher without passing its raw text through WestonPack's command
|
||||||
reconstruction. Do not move the mapping back to either side of
|
reconstruction. Do not move the mapping back to either side of
|
||||||
`westonwrap.sh`.
|
`westonwrap.sh`.
|
||||||
|
|
||||||
Always pass `netfishing.gptk`, which explicitly unassigns every direct and
|
Always pass `straywild.gptk`, which explicitly unassigns every direct and
|
||||||
hotkey binding with GPTOKEYB's `\"` value. This keeps GPTOKEYB from injecting
|
hotkey binding with GPTOKEYB's `\"` value. This keeps GPTOKEYB from injecting
|
||||||
keyboard or mouse events on top of Godot's native controller input and retains
|
keyboard or mouse events on top of Godot's native controller input and retains
|
||||||
the device-specific kill chord. Supplying the explicit passthrough map also
|
the device-specific kill chord. Supplying the explicit passthrough map also
|
||||||
|
|
@ -209,8 +213,8 @@ The light profile passes these Godot options:
|
||||||
- `--max-fps 30`
|
- `--max-fps 30`
|
||||||
- `--audio-output-latency 40`
|
- `--audio-output-latency 40`
|
||||||
|
|
||||||
It also passes `NETFISHING_PERFORMANCE_PROFILE=light` and
|
It also passes `straywild_PERFORMANCE_PROFILE=light` and
|
||||||
`NETFISHING_LOW_END=1`. The game renders the 3D world at 37.5% linear
|
`straywild_LOW_END=1`. The game renders the 3D world at 37.5% linear
|
||||||
resolution with nearest-neighbor scaling, reducing 3D pixel work by about 86%
|
resolution with nearest-neighbor scaling, reducing 3D pixel work by about 86%
|
||||||
while the separately rendered UI retains its canonical resolution. The light
|
while the separately rendered UI retains its canonical resolution. The light
|
||||||
profile also:
|
profile also:
|
||||||
|
|
@ -244,7 +248,7 @@ omitted ambience or replace the micro textures with desktop-resolution assets.
|
||||||
The normal profile otherwise retains the full visual presentation.
|
The normal profile otherwise retains the full visual presentation.
|
||||||
|
|
||||||
To opt a capable device into the normal profile, create the persistent file
|
To opt a capable device into the normal profile, create the persistent file
|
||||||
`netfishing/conf/performance_profile` containing exactly:
|
`straywild/conf/performance_profile` containing exactly:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
normal
|
normal
|
||||||
|
|
@ -253,13 +257,13 @@ normal
|
||||||
On a typical muOS installation, the full path is:
|
On a typical muOS installation, the full path is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/mnt/mmc/ports/netfishing/conf/performance_profile
|
/mnt/mmc/ports/straywild/conf/performance_profile
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the file to `light`, or remove it, to restore the default. An externally
|
Set the file to `light`, or remove it, to restore the default. An externally
|
||||||
provided `NETFISHING_PERFORMANCE_PROFILE=normal` or `light` environment value
|
provided `straywild_PERFORMANCE_PROFILE=normal` or `light` environment value
|
||||||
takes precedence over the persistent file. Invalid values safely fall back to
|
takes precedence over the persistent file. Invalid values safely fall back to
|
||||||
the light profile and are reported in `netfishing/log.txt`.
|
the light profile and are reported in `straywild/log.txt`.
|
||||||
|
|
||||||
Do not use Godot's low processor mode for the light profile. It reduces idle
|
Do not use Godot's low processor mode for the light profile. It reduces idle
|
||||||
CPU usage by sleeping between updates and is not a game-performance
|
CPU usage by sleeping between updates and is not a game-performance
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
NETfishing
|
straywild
|
||||||
v0.18.0-alpha
|
v0.19.0-alpha
|
||||||
Alpha 0.18.0
|
Alpha 0.19.0
|
||||||
|
|
||||||
Thank you for trying this early private playtest.
|
Thank you for trying this early private playtest.
|
||||||
|
|
||||||
NETfishing is an early multiplayer fishing game. This alpha includes local
|
straywild is an early multiplayer fishing game. This alpha includes local
|
||||||
progression, player-hosted and dedicated multiplayer sessions, public room
|
progression, player-hosted and dedicated multiplayer sessions, public room
|
||||||
discovery, and direct UDP connections. Expect rough edges and please keep a
|
discovery, and direct UDP connections. Expect rough edges and please keep a
|
||||||
backup of any save or identity data you care about.
|
backup of any save or identity data you care about.
|
||||||
|
|
@ -12,15 +12,15 @@ backup of any save or identity data you care about.
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
|
|
||||||
1. Extract the entire ZIP into a new folder.
|
1. Extract the entire ZIP into a new folder.
|
||||||
2. Keep the executable and netfishing.pck together.
|
2. Keep the executable and straywild.pck together.
|
||||||
3. Launch netfishing.exe on Windows or netfishing on Linux.
|
3. Launch straywild.exe on Windows or straywild on Linux.
|
||||||
|
|
||||||
Windows may show a warning for an unsigned application. This private build is
|
Windows may show a warning for an unsigned application. This private build is
|
||||||
not code signed. Only run a copy received from the playtest organizer.
|
not code signed. Only run a copy received from the playtest organizer.
|
||||||
|
|
||||||
Linux users may need to allow execution:
|
Linux users may need to allow execution:
|
||||||
|
|
||||||
chmod +x netfishing
|
chmod +x straywild
|
||||||
|
|
||||||
CONTROLS
|
CONTROLS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# NETfishing documentation
|
# straywild documentation
|
||||||
|
|
||||||
This directory is the single home for maintained project documentation.
|
This directory is the single home for maintained project documentation.
|
||||||
Start here instead of searching feature, asset, world, or script directories
|
Start here instead of searching feature, asset, world, or script directories
|
||||||
|
|
@ -17,10 +17,10 @@ for local README files.
|
||||||
|
|
||||||
## Related repositories
|
## Related repositories
|
||||||
|
|
||||||
- [Discovery service API](https://forge.makearmy.io/woofmeow/netfishing-discovery-server/src/branch/main/docs/API.md)
|
- [Discovery service API](https://forge.makearmy.io/woofmeow/straywild-discovery-server/src/branch/main/docs/API.md)
|
||||||
stays with the service implementation and defines its versioned HTTP
|
stays with the service implementation and defines its versioned HTTP
|
||||||
contract.
|
contract.
|
||||||
- [Dedicated-server packaging](https://forge.makearmy.io/woofmeow/netfishing-dedicated-server/src/branch/main/README.md)
|
- [Dedicated-server packaging](https://forge.makearmy.io/woofmeow/straywild-dedicated-server/src/branch/main/README.md)
|
||||||
stays with its installer and update scripts. It consumes this repository's
|
stays with its installer and update scripts. It consumes this repository's
|
||||||
attribution and legal notices from the exact pinned game commit instead of
|
attribution and legal notices from the exact pinned game commit instead of
|
||||||
maintaining copies.
|
maintaining copies.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*"
|
exclude_filter="builds/*,scripts/*"
|
||||||
export_path="builds/v0.18.0-alpha/windows-x86_64/NETfishing.exe"
|
export_path="builds/v0.19.0-alpha/windows-x86_64/straywild.exe"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
@ -32,16 +32,16 @@ codesign/digest_algorithm=1
|
||||||
codesign/description=""
|
codesign/description=""
|
||||||
codesign/custom_options=PackedStringArray()
|
codesign/custom_options=PackedStringArray()
|
||||||
application/modify_resources=true
|
application/modify_resources=true
|
||||||
application/icon="res://art/exported/system_icons/netfishing.ico"
|
application/icon="res://art/exported/system_icons/straywild.ico"
|
||||||
application/console_wrapper_icon=""
|
application/console_wrapper_icon=""
|
||||||
application/icon_interpolation=4
|
application/icon_interpolation=0
|
||||||
application/file_version="0.18.0.0"
|
application/file_version="0.19.0.0"
|
||||||
application/product_version="0.18.0.0"
|
application/product_version="0.19.0.0"
|
||||||
application/company_name="Woofmeow"
|
application/company_name="Woofmeow"
|
||||||
application/product_name="NETfishing"
|
application/product_name="straywild"
|
||||||
application/file_description="NETfishing v0.18.0-alpha"
|
application/file_description="straywild v0.19.0-alpha"
|
||||||
application/copyright="Copyright © 2026 Woofmeow"
|
application/copyright="Copyright © 2026 Woofmeow"
|
||||||
application/trademarks="NETfishing and Woofmeow branding is reserved; see TRADEMARKS.md"
|
application/trademarks="straywild and Woofmeow branding is reserved; see TRADEMARKS.md"
|
||||||
application/export_angle=0
|
application/export_angle=0
|
||||||
ssh_remote_deploy/enabled=false
|
ssh_remote_deploy/enabled=false
|
||||||
ssh_remote_deploy/host="user@host_ip"
|
ssh_remote_deploy/host="user@host_ip"
|
||||||
|
|
@ -62,7 +62,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*"
|
exclude_filter="builds/*,scripts/*"
|
||||||
export_path="builds/v0.18.0-alpha/linux-arm64/NETfishing.arm64"
|
export_path="builds/v0.19.0-alpha/linux-arm64/straywild.arm64"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
@ -92,7 +92,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*"
|
exclude_filter="builds/*,scripts/*"
|
||||||
export_path="builds/v0.18.0-alpha/macos/NETfishing.zip"
|
export_path="builds/v0.19.0-alpha/macos/straywild.zip"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
@ -106,10 +106,10 @@ script_export_mode=2
|
||||||
custom_template/debug=""
|
custom_template/debug=""
|
||||||
custom_template/release=""
|
custom_template/release=""
|
||||||
application/bundle_identifier="io.woofmeow.netfishing"
|
application/bundle_identifier="io.woofmeow.netfishing"
|
||||||
application/icon="res://art/exported/system_icons/netfishing_1024.png"
|
application/icon="res://art/exported/system_icons/straywild_1024.png"
|
||||||
application/icon_interpolation=0
|
application/icon_interpolation=0
|
||||||
application/short_version="0.18.0"
|
application/short_version="0.19.0"
|
||||||
application/version="0.18.0"
|
application/version="0.19.0"
|
||||||
application/architecture="universal"
|
application/architecture="universal"
|
||||||
codesign/enable=false
|
codesign/enable=false
|
||||||
notarization/enable=false
|
notarization/enable=false
|
||||||
|
|
@ -125,7 +125,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*,tests/*"
|
exclude_filter="builds/*,scripts/*,tests/*"
|
||||||
export_path="builds/v0.18.0-alpha/server-linux-x86_64/NETfishingServer.x86_64"
|
export_path="builds/v0.19.0-alpha/server-linux-x86_64/straywildServer.x86_64"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
@ -155,7 +155,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*"
|
exclude_filter="builds/*,scripts/*"
|
||||||
export_path="builds/v0.18.0-alpha/android/NETfishing.apk"
|
export_path="builds/v0.19.0-alpha/android/straywild.apk"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
@ -176,10 +176,10 @@ architectures/armeabi-v7a=false
|
||||||
architectures/arm64-v8a=true
|
architectures/arm64-v8a=true
|
||||||
architectures/x86=false
|
architectures/x86=false
|
||||||
architectures/x86_64=false
|
architectures/x86_64=false
|
||||||
version/code=180000
|
version/code=190000
|
||||||
version/name="v0.18.0-alpha"
|
version/name="v0.19.0-alpha"
|
||||||
package/unique_name="io.woofmeow.netfishing"
|
package/unique_name="io.woofmeow.netfishing"
|
||||||
package/name="NETfishing"
|
package/name="straywild"
|
||||||
package/signed=true
|
package/signed=true
|
||||||
package/app_category=0
|
package/app_category=0
|
||||||
package/retain_data_on_uninstall=false
|
package/retain_data_on_uninstall=false
|
||||||
|
|
@ -187,7 +187,7 @@ package/exclude_from_recents=false
|
||||||
package/show_in_android_tv=false
|
package/show_in_android_tv=false
|
||||||
package/show_in_app_library=true
|
package/show_in_app_library=true
|
||||||
package/show_as_launcher_app=true
|
package/show_as_launcher_app=true
|
||||||
launcher_icons/main_192x192="res://art/exported/system_icons/netfishing_256.png"
|
launcher_icons/main_192x192="res://art/exported/system_icons/straywild_256.png"
|
||||||
graphics/opengl_debug=false
|
graphics/opengl_debug=false
|
||||||
screen/immersive_mode=true
|
screen/immersive_mode=true
|
||||||
screen/edge_to_edge=false
|
screen/edge_to_edge=false
|
||||||
|
|
@ -214,7 +214,7 @@ custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
include_filter="LICENSE,ASSET-LICENSE.md,TRADEMARKS.md,docs/ATTRIBUTION.md,ui/fonts/*LICENSE.txt"
|
||||||
exclude_filter="builds/*,scripts/*"
|
exclude_filter="builds/*,scripts/*"
|
||||||
export_path="builds/v0.18.0-alpha/linux-x86_64/NETfishing.x86_64"
|
export_path="builds/v0.19.0-alpha/linux-x86_64/straywild.x86_64"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ var _network_session: NetworkSessionType
|
||||||
var _network_fishing: NetworkFishingServiceType
|
var _network_fishing: NetworkFishingServiceType
|
||||||
var _world_time: WorldTimeServiceType
|
var _world_time: WorldTimeServiceType
|
||||||
var _world_weather: WorldWeatherServiceType
|
var _world_weather: WorldWeatherServiceType
|
||||||
|
var _fishable_water_regions_resolver := Callable()
|
||||||
var _active_player: PlayerType
|
var _active_player: PlayerType
|
||||||
var _state_time_remaining: float = 0.0
|
var _state_time_remaining: float = 0.0
|
||||||
var _cast_charge: float = 0.0
|
var _cast_charge: float = 0.0
|
||||||
|
|
@ -222,6 +223,7 @@ func setup(
|
||||||
network_fishing: NetworkFishingServiceType = null,
|
network_fishing: NetworkFishingServiceType = null,
|
||||||
world_time: WorldTimeServiceType = null,
|
world_time: WorldTimeServiceType = null,
|
||||||
world_weather: WorldWeatherServiceType = null,
|
world_weather: WorldWeatherServiceType = null,
|
||||||
|
fishable_water_regions_resolver: Callable = Callable(),
|
||||||
) -> void:
|
) -> void:
|
||||||
_local_player = local_player
|
_local_player = local_player
|
||||||
_local_inventory = local_inventory
|
_local_inventory = local_inventory
|
||||||
|
|
@ -242,6 +244,7 @@ func setup(
|
||||||
_network_fishing = network_fishing
|
_network_fishing = network_fishing
|
||||||
_world_time = world_time
|
_world_time = world_time
|
||||||
_world_weather = world_weather
|
_world_weather = world_weather
|
||||||
|
_fishable_water_regions_resolver = fishable_water_regions_resolver
|
||||||
if (
|
if (
|
||||||
_network_session != null
|
_network_session != null
|
||||||
and not _network_session.state_changed.is_connected(
|
and not _network_session.state_changed.is_connected(
|
||||||
|
|
@ -1664,6 +1667,47 @@ func build_network_context(
|
||||||
return _build_fishing_context(region)
|
return _build_fishing_context(region)
|
||||||
|
|
||||||
|
|
||||||
|
func is_species_available_now(fish: FishDataType) -> bool:
|
||||||
|
if fish == null or not fish.is_selectable():
|
||||||
|
return false
|
||||||
|
var season := (
|
||||||
|
_world_time.get_season()
|
||||||
|
if _world_time != null
|
||||||
|
else CalendarSeason.UNKNOWN
|
||||||
|
)
|
||||||
|
if not fish.is_available_in_season(season):
|
||||||
|
return false
|
||||||
|
if fish.collection_method != FishDataType.CollectionMethod.FISHING:
|
||||||
|
return true
|
||||||
|
for region: FishableWaterRegionType in _get_logbook_water_regions():
|
||||||
|
if (
|
||||||
|
region == null
|
||||||
|
or region.fish_pool == null
|
||||||
|
or region.fish_pool.get_fish_by_id(fish.id) == null
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
var context := _build_fishing_context(region)
|
||||||
|
if not fish.is_allowed_in_water(context.water_type):
|
||||||
|
continue
|
||||||
|
if fish.availability == null or fish.availability.is_available(context):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _get_logbook_water_regions() -> Array[FishableWaterRegionType]:
|
||||||
|
var regions: Array[FishableWaterRegionType] = []
|
||||||
|
if not _fishable_water_regions_resolver.is_valid():
|
||||||
|
return regions
|
||||||
|
var resolved: Variant = _fishable_water_regions_resolver.call()
|
||||||
|
if resolved is not Array:
|
||||||
|
return regions
|
||||||
|
for value: Variant in resolved:
|
||||||
|
var region := value as FishableWaterRegionType
|
||||||
|
if region != null and is_instance_valid(region):
|
||||||
|
regions.append(region)
|
||||||
|
return regions
|
||||||
|
|
||||||
|
|
||||||
func _get_active_bait_tags() -> Array[StringName]:
|
func _get_active_bait_tags() -> Array[StringName]:
|
||||||
if _local_player == null or _item_catalog == null:
|
if _local_player == null or _item_catalog == null:
|
||||||
return []
|
return []
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,16 @@ func configure(
|
||||||
entity_id = configured_entity_id
|
entity_id = configured_entity_id
|
||||||
data = configured_data
|
data = configured_data
|
||||||
type_id = data.type_id if data != null else StringName()
|
type_id = data.type_id if data != null else StringName()
|
||||||
|
# Establish the authoritative transform before constructing transient visuals.
|
||||||
|
# Effects emitted before this point would begin at the default world origin.
|
||||||
|
apply_network_state(position, yaw, true)
|
||||||
if data != null and data.is_stationary_hotspot():
|
if data != null and data.is_stationary_hotspot():
|
||||||
_ensure_water_spurt_visual()
|
_ensure_water_spurt_visual()
|
||||||
_water_spurt_elapsed = (
|
_water_spurt_elapsed = (
|
||||||
float(abs(hash(entity_id)) % 1000) / 1000.0
|
float(abs(hash(entity_id)) % 1000) / 1000.0
|
||||||
* WATER_SPURT_INTERVAL_SECONDS
|
* WATER_SPURT_INTERVAL_SECONDS
|
||||||
)
|
)
|
||||||
|
_emit_water_spurt()
|
||||||
else:
|
else:
|
||||||
_ensure_visual()
|
_ensure_visual()
|
||||||
if data != null and data.catch_data != null and _sprite != null:
|
if data != null and data.catch_data != null and _sprite != null:
|
||||||
|
|
@ -50,7 +54,6 @@ func configure(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
_sprite.rotation_degrees.x = data.sprite_tilt_degrees
|
_sprite.rotation_degrees.x = data.sprite_tilt_degrees
|
||||||
apply_network_state(position, yaw, true)
|
|
||||||
|
|
||||||
|
|
||||||
func apply_network_state(
|
func apply_network_state(
|
||||||
|
|
@ -147,7 +150,6 @@ func _ensure_water_spurt_visual() -> void:
|
||||||
hole.mesh = hole_mesh
|
hole.mesh = hole_mesh
|
||||||
hole.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
hole.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||||
_water_spurt_root.add_child(hole)
|
_water_spurt_root.add_child(hole)
|
||||||
_emit_water_spurt()
|
|
||||||
|
|
||||||
|
|
||||||
func _emit_water_spurt() -> void:
|
func _emit_water_spurt() -> void:
|
||||||
|
|
@ -159,6 +161,7 @@ func _emit_water_spurt() -> void:
|
||||||
particles.amount = 6
|
particles.amount = 6
|
||||||
particles.lifetime = 0.42
|
particles.lifetime = 0.42
|
||||||
particles.one_shot = true
|
particles.one_shot = true
|
||||||
|
particles.local_coords = true
|
||||||
particles.explosiveness = 1.0
|
particles.explosiveness = 1.0
|
||||||
particles.direction = Vector3.UP
|
particles.direction = Vector3.UP
|
||||||
particles.spread = 32.0
|
particles.spread = 32.0
|
||||||
|
|
|
||||||
67
main/main.gd
|
|
@ -277,6 +277,7 @@ var _rain_ambience: RainAmbienceType
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_data_root.prepare_legacy_user_data()
|
||||||
_performance_profile = RuntimePerformanceProfileType.from_environment()
|
_performance_profile = RuntimePerformanceProfileType.from_environment()
|
||||||
_dedicated_runtime = _is_dedicated_server_runtime()
|
_dedicated_runtime = _is_dedicated_server_runtime()
|
||||||
if _dedicated_runtime:
|
if _dedicated_runtime:
|
||||||
|
|
@ -294,7 +295,7 @@ func _ready() -> void:
|
||||||
_configure_presentation_performance_profile(
|
_configure_presentation_performance_profile(
|
||||||
_performance_profile.is_light()
|
_performance_profile.is_light()
|
||||||
)
|
)
|
||||||
DisplayServer.window_set_title("NETfishing")
|
DisplayServer.window_set_title("straywild")
|
||||||
_rain_ambience = RainAmbienceType.new()
|
_rain_ambience = RainAmbienceType.new()
|
||||||
_rain_ambience.name = "RainAmbience"
|
_rain_ambience.name = "RainAmbience"
|
||||||
add_child(_rain_ambience)
|
add_child(_rain_ambience)
|
||||||
|
|
@ -324,11 +325,12 @@ func _ready() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _configure_presentation_performance_profile(light_profile: bool) -> void:
|
func _configure_presentation_performance_profile(light_profile: bool) -> void:
|
||||||
_game_ui.get_title_screen().set_minimal_presentation(light_profile)
|
|
||||||
_game_ui.set_light_performance_profile(light_profile)
|
_game_ui.set_light_performance_profile(light_profile)
|
||||||
var title_water_material := _title_background.material as ShaderMaterial
|
var title_background_material := (
|
||||||
if title_water_material != null:
|
_title_background.material as ShaderMaterial
|
||||||
title_water_material.set_shader_parameter(
|
)
|
||||||
|
if title_background_material != null:
|
||||||
|
title_background_material.set_shader_parameter(
|
||||||
"animation_enabled",
|
"animation_enabled",
|
||||||
not light_profile,
|
not light_profile,
|
||||||
)
|
)
|
||||||
|
|
@ -461,7 +463,7 @@ func _print_dedicated_metrics() -> void:
|
||||||
metrics["gatherables"] = _network_world_spawns.call(
|
metrics["gatherables"] = _network_world_spawns.call(
|
||||||
"get_network_metrics"
|
"get_network_metrics"
|
||||||
)
|
)
|
||||||
print("NETfishing server metrics: %s" % JSON.stringify(metrics))
|
print("straywild server metrics: %s" % JSON.stringify(metrics))
|
||||||
|
|
||||||
|
|
||||||
func _start_dedicated_server() -> void:
|
func _start_dedicated_server() -> void:
|
||||||
|
|
@ -470,10 +472,7 @@ func _start_dedicated_server() -> void:
|
||||||
_fail_dedicated_server(config.error_message)
|
_fail_dedicated_server(config.error_message)
|
||||||
return
|
return
|
||||||
var data_path: String = config.data_directory
|
var data_path: String = config.data_directory
|
||||||
var manifest_path: String = data_path.path_join(
|
if not _data_root.has_data_manifest(data_path):
|
||||||
PlayerDataRoot.MANIFEST_FILENAME
|
|
||||||
)
|
|
||||||
if not FileAccess.file_exists(manifest_path):
|
|
||||||
var created: Dictionary = _data_root.create_unbound_root(data_path)
|
var created: Dictionary = _data_root.create_unbound_root(data_path)
|
||||||
if not bool(created.get("ok", false)):
|
if not bool(created.get("ok", false)):
|
||||||
_fail_dedicated_server(str(created.get(
|
_fail_dedicated_server(str(created.get(
|
||||||
|
|
@ -556,7 +555,7 @@ func _start_dedicated_server() -> void:
|
||||||
_fail_dedicated_server(_discovery.get_host_status_message())
|
_fail_dedicated_server(_discovery.get_host_status_message())
|
||||||
return
|
return
|
||||||
print(
|
print(
|
||||||
"NETfishing dedicated server ready: %s on %s:%d (%d players, %s, timezone %s)"
|
"straywild dedicated server ready: %s on %s:%d (%d players, %s, timezone %s)"
|
||||||
% [
|
% [
|
||||||
config.server_name,
|
config.server_name,
|
||||||
config.bind_address,
|
config.bind_address,
|
||||||
|
|
@ -921,6 +920,7 @@ func _initialize_application(dedicated: bool) -> void:
|
||||||
_network_fishing,
|
_network_fishing,
|
||||||
_world_time,
|
_world_time,
|
||||||
_world_weather,
|
_world_weather,
|
||||||
|
Callable(_test_world, "get_fishable_water_regions"),
|
||||||
)
|
)
|
||||||
if dedicated:
|
if dedicated:
|
||||||
return
|
return
|
||||||
|
|
@ -972,6 +972,7 @@ func _initialize_application(dedicated: bool) -> void:
|
||||||
_network_session,
|
_network_session,
|
||||||
_interface_fonts,
|
_interface_fonts,
|
||||||
)
|
)
|
||||||
|
_game_ui.data_root_changed.connect(_on_data_root_changed)
|
||||||
_game_ui.setup_controller_mapping(_controller_mapping_manager)
|
_game_ui.setup_controller_mapping(_controller_mapping_manager)
|
||||||
_ui_pixelation.setup_controller_mapping(_controller_mapping_manager)
|
_ui_pixelation.setup_controller_mapping(_controller_mapping_manager)
|
||||||
_game_ui.setup_keyboard_mouse_mapping(_keyboard_mouse_mapping_manager)
|
_game_ui.setup_keyboard_mouse_mapping(_keyboard_mouse_mapping_manager)
|
||||||
|
|
@ -1006,7 +1007,8 @@ func _initialize_application(dedicated: bool) -> void:
|
||||||
_game_ui,
|
_game_ui,
|
||||||
_game_ui.get_screen_fade(),
|
_game_ui.get_screen_fade(),
|
||||||
_test_world.get_player_water_triggers(),
|
_test_world.get_player_water_triggers(),
|
||||||
_test_world.get_safe_respawn_points()
|
_test_world.get_safe_respawn_points(),
|
||||||
|
Callable(_test_world, "get_water_recovery_position"),
|
||||||
)
|
)
|
||||||
_ui_pixelation.effective_pixel_size_changed.connect(
|
_ui_pixelation.effective_pixel_size_changed.connect(
|
||||||
_on_effective_ui_pixel_size_changed
|
_on_effective_ui_pixel_size_changed
|
||||||
|
|
@ -1096,7 +1098,7 @@ func _initialize_application(dedicated: bool) -> void:
|
||||||
func _show_data_root_setup() -> void:
|
func _show_data_root_setup() -> void:
|
||||||
if _data_setup_dialog == null:
|
if _data_setup_dialog == null:
|
||||||
_data_setup_dialog = ConfirmationDialog.new()
|
_data_setup_dialog = ConfirmationDialog.new()
|
||||||
_data_setup_dialog.title = "NETfishing player data"
|
_data_setup_dialog.title = "straywild player data"
|
||||||
_data_setup_dialog.ok_button_text = "Use This Folder"
|
_data_setup_dialog.ok_button_text = "Use This Folder"
|
||||||
_data_setup_dialog.cancel_button_text = "Quit"
|
_data_setup_dialog.cancel_button_text = "Quit"
|
||||||
_data_setup_dialog.confirmed.connect(_use_default_data_root)
|
_data_setup_dialog.confirmed.connect(_use_default_data_root)
|
||||||
|
|
@ -1113,14 +1115,14 @@ func _show_data_root_setup() -> void:
|
||||||
var default_path: String = _data_root.default_visible_path()
|
var default_path: String = _data_root.default_visible_path()
|
||||||
var legacy: bool = PortableDataMigration.legacy_files_present()
|
var legacy: bool = PortableDataMigration.legacy_files_present()
|
||||||
_data_setup_dialog.dialog_text = (
|
_data_setup_dialog.dialog_text = (
|
||||||
("Move your existing NETfishing data to an easy-to-find folder."
|
("Move your existing straywild data to an easy-to-find folder."
|
||||||
if legacy else "Choose where NETfishing stores your player data.")
|
if legacy else "Choose where straywild stores your player data.")
|
||||||
+ "\n\n%s\n\nYou can choose a Syncthing folder."
|
+ "\n\n%s\n\nYou can choose a Syncthing folder."
|
||||||
% (default_path if not default_path.is_empty() else "Choose a folder")
|
% (default_path if not default_path.is_empty() else "Choose a folder")
|
||||||
)
|
)
|
||||||
_data_setup_dialog.ok_button_text = (
|
_data_setup_dialog.ok_button_text = (
|
||||||
(
|
(
|
||||||
"Move to Documents/NETFISHING"
|
"Move to Documents/straywild"
|
||||||
if legacy else "Use This Folder"
|
if legacy else "Use This Folder"
|
||||||
)
|
)
|
||||||
if not default_path.is_empty()
|
if not default_path.is_empty()
|
||||||
|
|
@ -1129,7 +1131,7 @@ func _show_data_root_setup() -> void:
|
||||||
_data_setup_current_button.visible = not default_path.is_empty()
|
_data_setup_current_button.visible = not default_path.is_empty()
|
||||||
if not _data_root.error_message.is_empty():
|
if not _data_root.error_message.is_empty():
|
||||||
_data_setup_dialog.dialog_text = (
|
_data_setup_dialog.dialog_text = (
|
||||||
"Your NETfishing data folder is unavailable.\n\n%s"
|
"Your straywild data folder is unavailable.\n\n%s"
|
||||||
% _data_root.error_message
|
% _data_root.error_message
|
||||||
)
|
)
|
||||||
_data_setup_dialog.popup_centered(Vector2i(640, 360))
|
_data_setup_dialog.popup_centered(Vector2i(640, 360))
|
||||||
|
|
@ -1265,11 +1267,11 @@ func _activate_selected_data_path(path: String, app_data: bool = false) -> void:
|
||||||
func _show_existing_root_choice(path: String) -> void:
|
func _show_existing_root_choice(path: String) -> void:
|
||||||
_pending_existing_root_path = path
|
_pending_existing_root_path = path
|
||||||
var dialog: ConfirmationDialog = ConfirmationDialog.new()
|
var dialog: ConfirmationDialog = ConfirmationDialog.new()
|
||||||
dialog.title = "Existing NETfishing data"
|
dialog.title = "Existing straywild data"
|
||||||
dialog.ok_button_text = "Use Data Already in Selected Folder"
|
dialog.ok_button_text = "Use Data Already in Selected Folder"
|
||||||
dialog.cancel_button_text = "Cancel"
|
dialog.cancel_button_text = "Cancel"
|
||||||
dialog.dialog_text = (
|
dialog.dialog_text = (
|
||||||
"This folder already contains NETfishing player data.\n\n"
|
"This folder already contains straywild player data.\n\n"
|
||||||
+ "Choose which complete data set to use. Data is never merged automatically."
|
+ "Choose which complete data set to use. Data is never merged automatically."
|
||||||
)
|
)
|
||||||
dialog.add_button(
|
dialog.add_button(
|
||||||
|
|
@ -1343,6 +1345,18 @@ func _on_data_root_status(message: String) -> void:
|
||||||
_configure_popup_dialog.call_deferred(dialog, dialog.get_ok_button())
|
_configure_popup_dialog.call_deferred(dialog, dialog.get_ok_button())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_data_root_changed() -> void:
|
||||||
|
_save_manager.set_autosave_enabled(false)
|
||||||
|
_save_manager.cancel_pending_autosave()
|
||||||
|
_configure_portable_stores()
|
||||||
|
if not _network_profile_service.reload_persisted_profile():
|
||||||
|
push_warning("The selected data folder's player profile could not be loaded.")
|
||||||
|
_network_session.set_local_appearance_snapshot(
|
||||||
|
_appearance_store.get_snapshot()
|
||||||
|
)
|
||||||
|
_game_ui.get_title_screen().refresh_after_data_root_change()
|
||||||
|
|
||||||
|
|
||||||
func _on_server_trust_required(
|
func _on_server_trust_required(
|
||||||
endpoint: String,
|
endpoint: String,
|
||||||
expected_fingerprint: String,
|
expected_fingerprint: String,
|
||||||
|
|
@ -2332,17 +2346,9 @@ func _on_remote_recovery_requested(
|
||||||
peer_id,
|
peer_id,
|
||||||
"Fishing attempt ended."
|
"Fishing attempt ended."
|
||||||
)
|
)
|
||||||
var target_position: Vector3 = _test_world.get_player_spawn_transform().origin
|
var target_position := _test_world.get_water_recovery_position(
|
||||||
var nearest_distance: float = INF
|
entry_position
|
||||||
for point: SafeRespawnPoint in _test_world.get_safe_respawn_points():
|
)
|
||||||
if point == null or not point.enabled:
|
|
||||||
continue
|
|
||||||
var distance: float = point.get_horizontal_distance_squared(
|
|
||||||
entry_position
|
|
||||||
)
|
|
||||||
if distance < nearest_distance:
|
|
||||||
nearest_distance = distance
|
|
||||||
target_position = point.global_position
|
|
||||||
target_position.y += _water_recovery.respawn_height_offset
|
target_position.y += _water_recovery.respawn_height_offset
|
||||||
avatar.global_position = target_position
|
avatar.global_position = target_position
|
||||||
avatar.velocity = Vector3.ZERO
|
avatar.velocity = Vector3.ZERO
|
||||||
|
|
@ -2420,6 +2426,7 @@ func _apply_world(
|
||||||
spawn_transform,
|
spawn_transform,
|
||||||
_test_world.get_player_water_triggers(),
|
_test_world.get_player_water_triggers(),
|
||||||
_test_world.get_safe_respawn_points(),
|
_test_world.get_safe_respawn_points(),
|
||||||
|
Callable(_test_world, "get_water_recovery_position"),
|
||||||
)
|
)
|
||||||
_shoreline_ambience.configure(
|
_shoreline_ambience.configure(
|
||||||
_player,
|
_player,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
[ext_resource type="Script" uid="uid://dpiv6wttry0j4" path="res://network/player_data_root.gd" id="37_data_root"]
|
[ext_resource type="Script" uid="uid://dpiv6wttry0j4" path="res://network/player_data_root.gd" id="37_data_root"]
|
||||||
[ext_resource type="Script" uid="uid://bu5q4a8jfvxkf" path="res://network/identity_backup_service.gd" id="38_identity_backup"]
|
[ext_resource type="Script" uid="uid://bu5q4a8jfvxkf" path="res://network/identity_backup_service.gd" id="38_identity_backup"]
|
||||||
[ext_resource type="Script" uid="uid://djmxy6jibi5y3" path="res://ui/interface_font_controller.gd" id="39_fonts"]
|
[ext_resource type="Script" uid="uid://djmxy6jibi5y3" path="res://ui/interface_font_controller.gd" id="39_fonts"]
|
||||||
[ext_resource type="Shader" uid="uid://c8s1g7tn771du" path="res://ui/title_water_background.gdshader" id="40_title_water"]
|
[ext_resource type="Texture2D" uid="uid://doju2lbj2ghwa" path="res://world/generation/chunks/assets/chunk_0000_grass_lite.png" id="40_title_grass"]
|
||||||
[ext_resource type="Texture2D" uid="uid://f8a0cs0s7ler" path="res://art/patterns/pattern_tealdot.png" id="41_menu_pattern"]
|
[ext_resource type="Texture2D" uid="uid://f8a0cs0s7ler" path="res://art/patterns/pattern_tealdot.png" id="41_menu_pattern"]
|
||||||
[ext_resource type="Shader" uid="uid://byw3iub66qvog" path="res://ui/player_menu_pattern.gdshader" id="42_menu_pattern"]
|
[ext_resource type="Shader" uid="uid://byw3iub66qvog" path="res://ui/player_menu_pattern.gdshader" id="42_menu_pattern"]
|
||||||
[ext_resource type="Texture2D" uid="uid://b6xws1d2dnbnn" path="res://art/patterns/pattern_moneyfish.png" id="43_shop_pattern"]
|
[ext_resource type="Texture2D" uid="uid://b6xws1d2dnbnn" path="res://art/patterns/pattern_moneyfish.png" id="43_shop_pattern"]
|
||||||
|
|
@ -59,18 +59,12 @@
|
||||||
[ext_resource type="Script" path="res://network/network_world_spawn_service.gd" id="59_world_spawns"]
|
[ext_resource type="Script" path="res://network/network_world_spawn_service.gd" id="59_world_spawns"]
|
||||||
[ext_resource type="Script" path="res://gathering/gathering_controller.gd" id="60_gathering_controller"]
|
[ext_resource type="Script" path="res://gathering/gathering_controller.gd" id="60_gathering_controller"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water_native"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_grass_native"]
|
||||||
shader = ExtResource("40_title_water")
|
shader = ExtResource("42_menu_pattern")
|
||||||
shader_parameter/surface_color = Color(0.1, 0.45, 0.62, 1)
|
shader_parameter/pattern_texture = ExtResource("40_title_grass")
|
||||||
shader_parameter/middle_color = Color(0.055, 0.285, 0.4, 1)
|
shader_parameter/source_tile_size = Vector2(128, 128)
|
||||||
shader_parameter/depth_color = Color(0.02, 0.16, 0.27, 1)
|
shader_parameter/display_scale = 1.0
|
||||||
shader_parameter/virtual_pixel_density = Vector2(320, 180)
|
shader_parameter/scroll_velocity_pixels = Vector2(-7.5, -7.5)
|
||||||
shader_parameter/color_step_count = 14.0
|
|
||||||
shader_parameter/continuous_depth_blend = 0.12
|
|
||||||
shader_parameter/wave_speed = 0.1
|
|
||||||
shader_parameter/wave_scale = 2.4
|
|
||||||
shader_parameter/wave_strength = 0.012
|
|
||||||
shader_parameter/caustic_strength = 0.018
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_player_menu_pattern"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_player_menu_pattern"]
|
||||||
shader = ExtResource("42_menu_pattern")
|
shader = ExtResource("42_menu_pattern")
|
||||||
|
|
@ -139,7 +133,7 @@ layer = -1
|
||||||
|
|
||||||
[node name="TitleBackground" type="ColorRect" parent="TitleBackgroundLayer" unique_id=1768697365]
|
[node name="TitleBackground" type="ColorRect" parent="TitleBackgroundLayer" unique_id=1768697365]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
material = SubResource("ShaderMaterial_title_water_native")
|
material = SubResource("ShaderMaterial_title_grass_native")
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@ class_name RuntimePerformanceProfile
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
const PROFILE_ENVIRONMENT_VARIABLE: String = (
|
const PROFILE_ENVIRONMENT_VARIABLE: String = (
|
||||||
|
"straywild_PERFORMANCE_PROFILE"
|
||||||
|
)
|
||||||
|
const LEGACY_LIGHT_ENVIRONMENT_VARIABLE: String = "straywild_LOW_END"
|
||||||
|
const NETFISHING_PROFILE_ENVIRONMENT_VARIABLE := (
|
||||||
"NETFISHING_PERFORMANCE_PROFILE"
|
"NETFISHING_PERFORMANCE_PROFILE"
|
||||||
)
|
)
|
||||||
const LEGACY_LIGHT_ENVIRONMENT_VARIABLE: String = "NETFISHING_LOW_END"
|
const NETFISHING_LIGHT_ENVIRONMENT_VARIABLE := "NETFISHING_LOW_END"
|
||||||
const NORMAL_PROFILE: StringName = &"normal"
|
const NORMAL_PROFILE: StringName = &"normal"
|
||||||
const LIGHT_PROFILE: StringName = &"light"
|
const LIGHT_PROFILE: StringName = &"light"
|
||||||
const NORMAL_WORLD_RENDER_SCALE: float = 1.0
|
const NORMAL_WORLD_RENDER_SCALE: float = 1.0
|
||||||
|
|
@ -14,9 +18,19 @@ var _profile_name: StringName = NORMAL_PROFILE
|
||||||
|
|
||||||
|
|
||||||
static func from_environment() -> RuntimePerformanceProfile:
|
static func from_environment() -> RuntimePerformanceProfile:
|
||||||
|
var profile_name: String = OS.get_environment(
|
||||||
|
PROFILE_ENVIRONMENT_VARIABLE
|
||||||
|
)
|
||||||
|
if profile_name.is_empty():
|
||||||
|
profile_name = OS.get_environment(
|
||||||
|
NETFISHING_PROFILE_ENVIRONMENT_VARIABLE
|
||||||
|
)
|
||||||
return from_name(
|
return from_name(
|
||||||
StringName(OS.get_environment(PROFILE_ENVIRONMENT_VARIABLE)),
|
StringName(profile_name),
|
||||||
OS.get_environment(LEGACY_LIGHT_ENVIRONMENT_VARIABLE) == "1",
|
(
|
||||||
|
OS.get_environment(LEGACY_LIGHT_ENVIRONMENT_VARIABLE) == "1"
|
||||||
|
or OS.get_environment(NETFISHING_LIGHT_ENVIRONMENT_VARIABLE) == "1"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
## Enforces NETfishing's nearest-neighbor-only artwork policy at runtime.
|
## Enforces straywild's nearest-neighbor-only artwork policy at runtime.
|
||||||
##
|
##
|
||||||
## Godot uses separate texture-filter enums for CanvasItem and 3D materials.
|
## Godot uses separate texture-filter enums for CanvasItem and 3D materials.
|
||||||
## Applying both here prevents imported models, dynamically created controls,
|
## Applying both here prevents imported models, dynamically created controls,
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,13 @@ signal friend_invite_received(
|
||||||
signal friend_invite_finished(success: bool, message: String)
|
signal friend_invite_finished(success: bool, message: String)
|
||||||
|
|
||||||
const BASE_URL_SETTING: String = "network/discovery/base_url"
|
const BASE_URL_SETTING: String = "network/discovery/base_url"
|
||||||
const BASE_URL_ENVIRONMENT: String = "NETFISHING_DISCOVERY_URL"
|
const BASE_URL_ENVIRONMENT: String = "straywild_DISCOVERY_URL"
|
||||||
|
const LEGACY_BASE_URL_ENVIRONMENT: String = "NETFISHING_DISCOVERY_URL"
|
||||||
const SETTINGS_PATH: String = "user://network_discovery.cfg"
|
const SETTINGS_PATH: String = "user://network_discovery.cfg"
|
||||||
const DEFAULT_ROOM_NAME: String = "Player's Server"
|
const DEFAULT_ROOM_NAME: String = "Player's Server"
|
||||||
const LEGACY_DEFAULT_ROOM_NAME: String = "NETfishing Room"
|
const LEGACY_DEFAULT_ROOM_NAME: String = "straywild Room"
|
||||||
const LEGACY_DEDICATED_DEFAULT_ROOM_NAME: String = (
|
const LEGACY_DEDICATED_DEFAULT_ROOM_NAME: String = (
|
||||||
"NETfishing Dedicated Server"
|
"straywild Dedicated Server"
|
||||||
)
|
)
|
||||||
const ROOM_NAME_SUFFIX: String = "'s Server"
|
const ROOM_NAME_SUFFIX: String = "'s Server"
|
||||||
const MAX_ROOM_NAME_LENGTH: int = 48
|
const MAX_ROOM_NAME_LENGTH: int = 48
|
||||||
|
|
@ -33,7 +34,7 @@ const HEARTBEAT_INTERVAL_SECONDS: float = 15.0
|
||||||
const REQUEST_TIMEOUT_SECONDS: float = 8.0
|
const REQUEST_TIMEOUT_SECONDS: float = 8.0
|
||||||
const TRAVERSAL_POLL_INTERVAL_SECONDS: float = 1.0
|
const TRAVERSAL_POLL_INTERVAL_SECONDS: float = 1.0
|
||||||
const JOIN_PROBE_INTERVAL_SECONDS: float = 0.35
|
const JOIN_PROBE_INTERVAL_SECONDS: float = 0.35
|
||||||
const TRAVERSAL_PACKET_PREFIX: String = "NETFISHING_TRAVERSAL_V1 "
|
const TRAVERSAL_PACKET_PREFIX: String = "straywild_TRAVERSAL_V1 "
|
||||||
const UPNP_MAPPING_DURATION_SECONDS: int = 3600
|
const UPNP_MAPPING_DURATION_SECONDS: int = 3600
|
||||||
const UPNP_RENEW_INTERVAL_SECONDS: float = 2700.0
|
const UPNP_RENEW_INTERVAL_SECONDS: float = 2700.0
|
||||||
const UPNP_RETRY_INTERVAL_SECONDS: float = 300.0
|
const UPNP_RETRY_INTERVAL_SECONDS: float = 300.0
|
||||||
|
|
@ -553,6 +554,10 @@ func is_own_room(room: Dictionary) -> bool:
|
||||||
|
|
||||||
func _configured_base_url() -> String:
|
func _configured_base_url() -> String:
|
||||||
var value: String = OS.get_environment(BASE_URL_ENVIRONMENT).strip_edges()
|
var value: String = OS.get_environment(BASE_URL_ENVIRONMENT).strip_edges()
|
||||||
|
if value.is_empty():
|
||||||
|
value = OS.get_environment(
|
||||||
|
LEGACY_BASE_URL_ENVIRONMENT
|
||||||
|
).strip_edges()
|
||||||
if value.is_empty():
|
if value.is_empty():
|
||||||
value = str(ProjectSettings.get_setting(BASE_URL_SETTING, "")).strip_edges()
|
value = str(ProjectSettings.get_setting(BASE_URL_SETTING, "")).strip_edges()
|
||||||
while value.ends_with("/"):
|
while value.ends_with("/"):
|
||||||
|
|
@ -560,7 +565,7 @@ func _configured_base_url() -> String:
|
||||||
if not value.is_empty() and not (
|
if not value.is_empty() and not (
|
||||||
value.begins_with("https://") or value.begins_with("http://")
|
value.begins_with("https://") or value.begins_with("http://")
|
||||||
):
|
):
|
||||||
push_warning("Ignored invalid NETfishing discovery URL.")
|
push_warning("Ignored invalid straywild discovery URL.")
|
||||||
return ""
|
return ""
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
@ -809,7 +814,7 @@ func _on_traversal_request_completed(
|
||||||
var port: int = int(endpoint.get("port", 0))
|
var port: int = int(endpoint.get("port", 0))
|
||||||
if address.is_empty() or port < 1 or port > 65535:
|
if address.is_empty() or port < 1 or port > 65535:
|
||||||
continue
|
continue
|
||||||
var punch: PackedByteArray = "NETFISHING_PUNCH_V1".to_utf8_buffer()
|
var punch: PackedByteArray = "straywild_PUNCH_V1".to_utf8_buffer()
|
||||||
for _attempt: int in 3:
|
for _attempt: int in 3:
|
||||||
_session.send_traversal_packet(address, port, punch)
|
_session.send_traversal_packet(address, port, punch)
|
||||||
|
|
||||||
|
|
@ -895,13 +900,13 @@ func _configure_upnp_mapping(port: int) -> Dictionary:
|
||||||
var mapping_result: int = upnp.add_port_mapping(
|
var mapping_result: int = upnp.add_port_mapping(
|
||||||
port,
|
port,
|
||||||
port,
|
port,
|
||||||
"NETfishing",
|
"straywild",
|
||||||
"UDP",
|
"UDP",
|
||||||
UPNP_MAPPING_DURATION_SECONDS,
|
UPNP_MAPPING_DURATION_SECONDS,
|
||||||
)
|
)
|
||||||
if mapping_result == UPNP.UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED:
|
if mapping_result == UPNP.UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED:
|
||||||
mapping_result = upnp.add_port_mapping(
|
mapping_result = upnp.add_port_mapping(
|
||||||
port, port, "NETfishing", "UDP", 0
|
port, port, "straywild", "UDP", 0
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"success": mapping_result == UPNP.UPNP_RESULT_SUCCESS,
|
"success": mapping_result == UPNP.UPNP_RESULT_SUCCESS,
|
||||||
|
|
@ -1374,18 +1379,18 @@ func _discovery_version_mismatch_message(required_version: String) -> String:
|
||||||
match rejection:
|
match rejection:
|
||||||
NetworkProtocol.RejectionCode.CLIENT_OUTDATED:
|
NetworkProtocol.RejectionCode.CLIENT_OUTDATED:
|
||||||
return (
|
return (
|
||||||
"Your NETfishing version is out of date. Update to %s to "
|
"Your straywild version is out of date. Update to %s to "
|
||||||
+ "enable public discovery. This room will not be listed "
|
+ "enable public discovery. This room will not be listed "
|
||||||
+ "until you update."
|
+ "until you update."
|
||||||
) % required_version
|
) % required_version
|
||||||
NetworkProtocol.RejectionCode.SERVER_OUTDATED:
|
NetworkProtocol.RejectionCode.SERVER_OUTDATED:
|
||||||
return (
|
return (
|
||||||
"Public discovery is still on NETfishing %s. This room "
|
"Public discovery is still on straywild %s. This room "
|
||||||
+ "will not be listed until discovery is updated for %s."
|
+ "will not be listed until discovery is updated for %s."
|
||||||
) % [required_version, local_version]
|
) % [required_version, local_version]
|
||||||
_:
|
_:
|
||||||
return (
|
return (
|
||||||
"Public discovery requires NETfishing %s. This room will "
|
"Public discovery requires straywild %s. This room will "
|
||||||
+ "not be listed until both versions match."
|
+ "not be listed until both versions match."
|
||||||
) % required_version
|
) % required_version
|
||||||
|
|
||||||
|
|
@ -1577,4 +1582,4 @@ func _save_settings() -> void:
|
||||||
config.set_value("social", "share_presence", _presence_sharing)
|
config.set_value("social", "share_presence", _presence_sharing)
|
||||||
var error: Error = config.save(SETTINGS_PATH)
|
var error: Error = config.save(SETTINGS_PATH)
|
||||||
if error != OK:
|
if error != OK:
|
||||||
push_warning("Could not save local NETfishing discovery settings.")
|
push_warning("Could not save local straywild discovery settings.")
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_store_path = path
|
_store_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_namespaces.clear()
|
||||||
|
_loaded = false
|
||||||
|
_write_blocked = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func is_banned(host_fingerprint: String, target_fingerprint: String) -> bool:
|
func is_banned(host_fingerprint: String, target_fingerprint: String) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ extends Node
|
||||||
|
|
||||||
signal operation_finished(success: bool, message: String)
|
signal operation_finished(success: bool, message: String)
|
||||||
|
|
||||||
const MAGIC := "NETFISHING_IDENTITY_BACKUP"
|
const MAGIC := "straywild_IDENTITY_BACKUP"
|
||||||
|
const LEGACY_MAGIC := "NETFISHING_IDENTITY_BACKUP"
|
||||||
const FORMAT_VERSION := 1
|
const FORMAT_VERSION := 1
|
||||||
const MAX_BACKUP_BYTES := 256 * 1024
|
const MAX_BACKUP_BYTES := 256 * 1024
|
||||||
const MIN_PASSPHRASE_LENGTH := 12
|
const MIN_PASSPHRASE_LENGTH := 12
|
||||||
|
|
@ -110,8 +111,9 @@ func inspect_backup(
|
||||||
if json.parse(text) != OK or typeof(json.data) != TYPE_DICTIONARY:
|
if json.parse(text) != OK or typeof(json.data) != TYPE_DICTIONARY:
|
||||||
return {"ok": false}
|
return {"ok": false}
|
||||||
var data: Dictionary = json.data
|
var data: Dictionary = json.data
|
||||||
|
var legacy_backup: bool = data.get("magic") == LEGACY_MAGIC
|
||||||
if (
|
if (
|
||||||
data.get("magic") != MAGIC
|
data.get("magic") not in [MAGIC, LEGACY_MAGIC]
|
||||||
or data.get("format_version") != FORMAT_VERSION
|
or data.get("format_version") != FORMAT_VERSION
|
||||||
or data.get("identity_type") != expected_type
|
or data.get("identity_type") != expected_type
|
||||||
or data.get("algorithm") != NetworkIdentityCrypto.ALGORITHM
|
or data.get("algorithm") != NetworkIdentityCrypto.ALGORITHM
|
||||||
|
|
@ -134,12 +136,23 @@ func inspect_backup(
|
||||||
var signature: PackedByteArray = Marshalls.base64_to_raw(
|
var signature: PackedByteArray = Marshalls.base64_to_raw(
|
||||||
str(data.get("self_signature", ""))
|
str(data.get("self_signature", ""))
|
||||||
)
|
)
|
||||||
if not NetworkIdentityCrypto.verify_fields(
|
var public_key: CryptoKey = NetworkIdentityCrypto.load_public_key(public_pem)
|
||||||
NetworkIdentityCrypto.load_public_key(public_pem),
|
var backup_signature_valid: bool = (
|
||||||
"identity_backup_self_test",
|
NetworkIdentityCrypto.verify_legacy_fields(
|
||||||
[expected_type, fingerprint],
|
public_key,
|
||||||
signature,
|
"identity_backup_self_test",
|
||||||
):
|
[expected_type, fingerprint],
|
||||||
|
signature,
|
||||||
|
)
|
||||||
|
if legacy_backup
|
||||||
|
else NetworkIdentityCrypto.verify_fields(
|
||||||
|
public_key,
|
||||||
|
"identity_backup_self_test",
|
||||||
|
[expected_type, fingerprint],
|
||||||
|
signature,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not backup_signature_valid:
|
||||||
return {"ok": false}
|
return {"ok": false}
|
||||||
var fresh: PackedByteArray = NetworkIdentityCrypto.sign_fields(
|
var fresh: PackedByteArray = NetworkIdentityCrypto.sign_fields(
|
||||||
key, "identity_import_self_test", [fingerprint]
|
key, "identity_import_self_test", [fingerprint]
|
||||||
|
|
@ -189,7 +202,7 @@ func import_backup(
|
||||||
)
|
)
|
||||||
_finish(
|
_finish(
|
||||||
bool(result.get("ok", false)),
|
bool(result.get("ok", false)),
|
||||||
"Identity imported. Restart NETfishing before multiplayer."
|
"Identity imported. Restart straywild before multiplayer."
|
||||||
if bool(result.get("ok", false))
|
if bool(result.get("ok", false))
|
||||||
else "Could not install this identity backup.",
|
else "Could not install this identity backup.",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_store_path = path
|
_store_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_records.clear()
|
||||||
|
_loaded = false
|
||||||
|
_write_blocked = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func observe(fingerprint: String, display_name: String) -> String:
|
func observe(fingerprint: String, display_name: String) -> String:
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ const ALGORITHM: String = "RSA-3072-SHA256"
|
||||||
const FINGERPRINT_LENGTH: int = 64
|
const FINGERPRINT_LENGTH: int = 64
|
||||||
const MAX_PUBLIC_KEY_BYTES: int = 8192
|
const MAX_PUBLIC_KEY_BYTES: int = 8192
|
||||||
const MAX_SIGNATURE_BYTES: int = 1024
|
const MAX_SIGNATURE_BYTES: int = 1024
|
||||||
const DOMAIN_PREFIX: String = "NETFISHING"
|
const DOMAIN_PREFIX: String = "straywild"
|
||||||
|
const LEGACY_DOMAIN_PREFIX: String = "NETFISHING"
|
||||||
const IDENTITY_VERSION: String = "identity_v1"
|
const IDENTITY_VERSION: String = "identity_v1"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -50,8 +51,16 @@ static func secure_id(byte_count: int = 16) -> String:
|
||||||
|
|
||||||
|
|
||||||
static func canonical_bytes(domain: String, fields: Array) -> PackedByteArray:
|
static func canonical_bytes(domain: String, fields: Array) -> PackedByteArray:
|
||||||
|
return canonical_bytes_for_prefix(DOMAIN_PREFIX, domain, fields)
|
||||||
|
|
||||||
|
|
||||||
|
static func canonical_bytes_for_prefix(
|
||||||
|
prefix: String,
|
||||||
|
domain: String,
|
||||||
|
fields: Array,
|
||||||
|
) -> PackedByteArray:
|
||||||
var output := PackedByteArray()
|
var output := PackedByteArray()
|
||||||
_append_string(output, DOMAIN_PREFIX)
|
_append_string(output, prefix)
|
||||||
_append_string(output, IDENTITY_VERSION)
|
_append_string(output, IDENTITY_VERSION)
|
||||||
_append_string(output, domain)
|
_append_string(output, domain)
|
||||||
for value: Variant in fields:
|
for value: Variant in fields:
|
||||||
|
|
@ -117,6 +126,37 @@ static func verify_fields(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static func verify_legacy_fields(
|
||||||
|
public_key: CryptoKey,
|
||||||
|
domain: String,
|
||||||
|
fields: Array,
|
||||||
|
signature: PackedByteArray,
|
||||||
|
) -> bool:
|
||||||
|
if (
|
||||||
|
public_key == null
|
||||||
|
or signature.is_empty()
|
||||||
|
or signature.size() > MAX_SIGNATURE_BYTES
|
||||||
|
):
|
||||||
|
return false
|
||||||
|
var bytes: PackedByteArray = canonical_bytes_for_prefix(
|
||||||
|
LEGACY_DOMAIN_PREFIX,
|
||||||
|
domain,
|
||||||
|
fields,
|
||||||
|
)
|
||||||
|
if bytes.is_empty():
|
||||||
|
return false
|
||||||
|
var context := HashingContext.new()
|
||||||
|
if context.start(HashingContext.HASH_SHA256) != OK:
|
||||||
|
return false
|
||||||
|
context.update(bytes)
|
||||||
|
return Crypto.new().verify(
|
||||||
|
HashingContext.HASH_SHA256,
|
||||||
|
context.finish(),
|
||||||
|
signature,
|
||||||
|
public_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
static func load_public_key(public_pem: String) -> CryptoKey:
|
static func load_public_key(public_pem: String) -> CryptoKey:
|
||||||
var normalized := normalize_public_pem(public_pem)
|
var normalized := normalize_public_pem(public_pem)
|
||||||
if normalized.is_empty() or normalized.to_utf8_buffer().size() > MAX_PUBLIC_KEY_BYTES:
|
if normalized.is_empty() or normalized.to_utf8_buffer().size() > MAX_PUBLIC_KEY_BYTES:
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ var _future_version := false
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_profile_path = path
|
_profile_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_expected_hash = ""
|
||||||
|
_future_version = false
|
||||||
|
|
||||||
|
|
||||||
func _temp_path() -> String:
|
func _temp_path() -> String:
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,17 @@ func setup(
|
||||||
_apply_local_voice_to_avatar()
|
_apply_local_voice_to_avatar()
|
||||||
|
|
||||||
|
|
||||||
|
func reload_persisted_profile() -> bool:
|
||||||
|
if (
|
||||||
|
not _preferences.load_or_create()
|
||||||
|
or not _appearance_store.load_preferences()
|
||||||
|
):
|
||||||
|
return false
|
||||||
|
_apply_to_avatar(1, _appearance_store.get_snapshot())
|
||||||
|
_apply_local_voice_to_avatar()
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
func get_persisted_name() -> String:
|
func get_persisted_name() -> String:
|
||||||
return _preferences.display_name
|
return _preferences.display_name
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ extends RefCounted
|
||||||
|
|
||||||
const WorldLayoutType = preload("res://world/world_layout.gd")
|
const WorldLayoutType = preload("res://world/world_layout.gd")
|
||||||
|
|
||||||
const PROTOCOL_VERSION: int = 10
|
const PROTOCOL_VERSION: int = 11
|
||||||
const GAME_BUILD: String = "prealpha"
|
const GAME_BUILD: String = "prealpha"
|
||||||
const MAX_GAME_VERSION_LENGTH: int = 64
|
const MAX_GAME_VERSION_LENGTH: int = 64
|
||||||
const MAX_DISPLAY_NAME_LENGTH: int = 24
|
const MAX_DISPLAY_NAME_LENGTH: int = 24
|
||||||
|
|
@ -304,7 +304,7 @@ static func make_server_hello(
|
||||||
assigned_peer_id: int,
|
assigned_peer_id: int,
|
||||||
player_count: int,
|
player_count: int,
|
||||||
max_players: int,
|
max_players: int,
|
||||||
server_display_name: String = "NETfishing",
|
server_display_name: String = "straywild",
|
||||||
world_seed: int = DEFAULT_WORLD_SEED,
|
world_seed: int = DEFAULT_WORLD_SEED,
|
||||||
world_layout: StringName = WorldLayoutType.GENERATED,
|
world_layout: StringName = WorldLayoutType.GENERATED,
|
||||||
) -> Dictionary:
|
) -> Dictionary:
|
||||||
|
|
@ -372,17 +372,17 @@ static func rejection_text(code: int) -> String:
|
||||||
return "You are not permitted to join this server."
|
return "You are not permitted to join this server."
|
||||||
RejectionCode.CLIENT_OUTDATED:
|
RejectionCode.CLIENT_OUTDATED:
|
||||||
return (
|
return (
|
||||||
"Your NETfishing version is out of date. "
|
"Your straywild version is out of date. "
|
||||||
+ "Update the game to join this server."
|
+ "Update the game to join this server."
|
||||||
)
|
)
|
||||||
RejectionCode.SERVER_OUTDATED:
|
RejectionCode.SERVER_OUTDATED:
|
||||||
return (
|
return (
|
||||||
"This server is out of date. "
|
"This server is out of date. "
|
||||||
+ "The host needs to update NETfishing."
|
+ "The host needs to update straywild."
|
||||||
)
|
)
|
||||||
RejectionCode.VERSION_MISMATCH:
|
RejectionCode.VERSION_MISMATCH:
|
||||||
return (
|
return (
|
||||||
"This game and server use different NETfishing versions. "
|
"This game and server use different straywild versions. "
|
||||||
+ "Update both to the latest release."
|
+ "Update both to the latest release."
|
||||||
)
|
)
|
||||||
_:
|
_:
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ var _local_appearance_snapshot: Dictionary = (
|
||||||
)
|
)
|
||||||
var _moderation_disconnect_message := ""
|
var _moderation_disconnect_message := ""
|
||||||
var _host_port: int = 0
|
var _host_port: int = 0
|
||||||
var _session_display_name: String = "NETfishing Room"
|
var _session_display_name: String = "straywild Room"
|
||||||
var _dedicated_host: bool = false
|
var _dedicated_host: bool = false
|
||||||
var _configured_operator_fingerprints: Dictionary[String, bool] = {}
|
var _configured_operator_fingerprints: Dictionary[String, bool] = {}
|
||||||
var _session_operator_fingerprints: Dictionary[String, bool] = {}
|
var _session_operator_fingerprints: Dictionary[String, bool] = {}
|
||||||
|
|
@ -432,7 +432,7 @@ func set_peer_operator(
|
||||||
func set_session_display_name(value: String) -> void:
|
func set_session_display_name(value: String) -> void:
|
||||||
var cleaned: String = value.strip_edges().left(48)
|
var cleaned: String = value.strip_edges().left(48)
|
||||||
if cleaned.is_empty():
|
if cleaned.is_empty():
|
||||||
cleaned = "NETfishing Room"
|
cleaned = "straywild Room"
|
||||||
if cleaned == _session_display_name:
|
if cleaned == _session_display_name:
|
||||||
return
|
return
|
||||||
_session_display_name = cleaned
|
_session_display_name = cleaned
|
||||||
|
|
@ -1187,7 +1187,7 @@ func resolve_server_trust(accepted: bool) -> void:
|
||||||
if not _server_trust.trust(
|
if not _server_trust.trust(
|
||||||
get_current_endpoint(),
|
get_current_endpoint(),
|
||||||
str(_pending_server_proof["server_fingerprint"]),
|
str(_pending_server_proof["server_fingerprint"]),
|
||||||
"NETfishing",
|
"straywild",
|
||||||
):
|
):
|
||||||
_fail_identity("The server identity could not be pinned.")
|
_fail_identity("The server identity could not be pinned.")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -879,7 +879,7 @@ func export_canvas_png(canvas_id: String) -> String:
|
||||||
_emit_hud_state("paint something before exporting")
|
_emit_hud_state("paint something before exporting")
|
||||||
return ""
|
return ""
|
||||||
if _data_root == null or _data_root.root_path.is_empty():
|
if _data_root == null or _data_root.root_path.is_empty():
|
||||||
_emit_hud_state("choose a NETfishing data folder before exporting")
|
_emit_hud_state("choose a straywild data folder before exporting")
|
||||||
return ""
|
return ""
|
||||||
var export_directory: String = _artwork_directory()
|
var export_directory: String = _artwork_directory()
|
||||||
if DirAccess.make_dir_recursive_absolute(export_directory) != OK:
|
if DirAccess.make_dir_recursive_absolute(export_directory) != OK:
|
||||||
|
|
@ -990,7 +990,7 @@ func _stamp_entry_is_unlocked(entry: Dictionary) -> bool:
|
||||||
|
|
||||||
func _next_artwork_export_path(directory: String) -> String:
|
func _next_artwork_export_path(directory: String) -> String:
|
||||||
var date_time: Dictionary = Time.get_datetime_dict_from_system()
|
var date_time: Dictionary = Time.get_datetime_dict_from_system()
|
||||||
var stem: String = "netfishing-artwork-%04d%02d%02d-%02d%02d%02d" % [
|
var stem: String = "straywild-artwork-%04d%02d%02d-%02d%02d%02d" % [
|
||||||
int(date_time.get("year", 0)),
|
int(date_time.get("year", 0)),
|
||||||
int(date_time.get("month", 0)),
|
int(date_time.get("month", 0)),
|
||||||
int(date_time.get("day", 0)),
|
int(date_time.get("day", 0)),
|
||||||
|
|
|
||||||
|
|
@ -518,7 +518,12 @@ func _sample_surface_position(
|
||||||
)
|
)
|
||||||
if triangles.is_empty() or total_area <= 0.0:
|
if triangles.is_empty() or total_area <= 0.0:
|
||||||
return Vector3(INF, INF, INF)
|
return Vector3(INF, INF, INF)
|
||||||
var attempts: int = 48 if is_finite(maximum_distance) else 1
|
var validates_diggable_surface := not entry.diggable_area_id.is_empty()
|
||||||
|
var attempts: int = (
|
||||||
|
48
|
||||||
|
if validates_diggable_surface or is_finite(maximum_distance)
|
||||||
|
else 1
|
||||||
|
)
|
||||||
var fallback: Vector3 = Vector3(INF, INF, INF)
|
var fallback: Vector3 = Vector3(INF, INF, INF)
|
||||||
for _attempt: int in attempts:
|
for _attempt: int in attempts:
|
||||||
var roll: float = _rng.randf() * total_area
|
var roll: float = _rng.randf() * total_area
|
||||||
|
|
@ -534,12 +539,22 @@ func _sample_surface_position(
|
||||||
+ triangle[2] * barycentric_c
|
+ triangle[2] * barycentric_c
|
||||||
)
|
)
|
||||||
fallback = point
|
fallback = point
|
||||||
if (
|
var within_requested_distance := (
|
||||||
not is_finite(maximum_distance)
|
not is_finite(maximum_distance)
|
||||||
or Vector2(point.x - origin.x, point.z - origin.z).length()
|
or Vector2(point.x - origin.x, point.z - origin.z).length()
|
||||||
<= maximum_distance
|
<= maximum_distance
|
||||||
):
|
)
|
||||||
|
var valid_diggable_surface := (
|
||||||
|
not validates_diggable_surface
|
||||||
|
or _world.is_diggable_surface_point_valid(
|
||||||
|
entry.diggable_area_id,
|
||||||
|
point,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if within_requested_distance and valid_diggable_surface:
|
||||||
return point
|
return point
|
||||||
|
if validates_diggable_surface:
|
||||||
|
return Vector3(INF, INF, INF)
|
||||||
if origin.is_finite() and is_finite(maximum_distance):
|
if origin.is_finite() and is_finite(maximum_distance):
|
||||||
return origin
|
return origin
|
||||||
return fallback
|
return fallback
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,42 @@ const BOOTSTRAP_TEMP_PATH := "user://data_root_bootstrap.json.tmp"
|
||||||
const BOOTSTRAP_VERSION := 1
|
const BOOTSTRAP_VERSION := 1
|
||||||
const MANIFEST_VERSION := 1
|
const MANIFEST_VERSION := 1
|
||||||
const LAYOUT_VERSION := 1
|
const LAYOUT_VERSION := 1
|
||||||
const MANIFEST_FILENAME := "netfishing_data.json"
|
const MANIFEST_FILENAME := "straywild_data.json"
|
||||||
|
const LEGACY_MANIFEST_FILENAME := "netfishing_data.json"
|
||||||
const README_FILENAME := "README.txt"
|
const README_FILENAME := "README.txt"
|
||||||
const ENVIRONMENT_VARIABLE := "NETFISHING_DATA_DIR"
|
const ENVIRONMENT_VARIABLE := "straywild_DATA_DIR"
|
||||||
const CREATE_ENVIRONMENT_VARIABLE := "NETFISHING_CREATE_DATA_DIR"
|
const CREATE_ENVIRONMENT_VARIABLE := "straywild_CREATE_DATA_DIR"
|
||||||
const APPLICATION_ID := "netfishing"
|
const LEGACY_ENVIRONMENT_VARIABLE := "NETFISHING_DATA_DIR"
|
||||||
|
const LEGACY_CREATE_ENVIRONMENT_VARIABLE := "NETFISHING_CREATE_DATA_DIR"
|
||||||
|
const APPLICATION_ID := "straywild"
|
||||||
|
const LEGACY_APPLICATION_ID := "netfishing"
|
||||||
const APP_DATA_PORTABLE_PATH := "user://portable-data"
|
const APP_DATA_PORTABLE_PATH := "user://portable-data"
|
||||||
|
const LEGACY_USER_DIRECTORY_NAME := "NETFISHING"
|
||||||
|
const LEGACY_USER_FILES := [
|
||||||
|
"data_root_bootstrap.json",
|
||||||
|
"data_root_bootstrap.json.backup",
|
||||||
|
"network_discovery.cfg",
|
||||||
|
"player_settings.json",
|
||||||
|
"player_settings.json.backup",
|
||||||
|
"controller_mappings.json",
|
||||||
|
"controller_mappings.json.backup",
|
||||||
|
"keyboard_mouse_bindings.json",
|
||||||
|
"keyboard_mouse_bindings.json.backup",
|
||||||
|
"player_save.json",
|
||||||
|
"network_profile.json",
|
||||||
|
"player_appearance.json",
|
||||||
|
"saved_servers.json",
|
||||||
|
"known_players.json",
|
||||||
|
"player_relationships.json",
|
||||||
|
"server_trust.json",
|
||||||
|
"host_bans.json",
|
||||||
|
"player_identity.key",
|
||||||
|
"player_identity.pub",
|
||||||
|
"player_identity.json",
|
||||||
|
"host_identity.key",
|
||||||
|
"host_identity.pub",
|
||||||
|
"host_identity.json",
|
||||||
|
]
|
||||||
const PATH_ALLOWED: StringName = &"allowed"
|
const PATH_ALLOWED: StringName = &"allowed"
|
||||||
const PATH_SOURCE_PROJECT: StringName = &"source_project"
|
const PATH_SOURCE_PROJECT: StringName = &"source_project"
|
||||||
const PATH_INSTALLATION: StringName = &"installation"
|
const PATH_INSTALLATION: StringName = &"installation"
|
||||||
|
|
@ -37,23 +67,29 @@ var override_active := false
|
||||||
|
|
||||||
|
|
||||||
func resolve() -> bool:
|
func resolve() -> bool:
|
||||||
|
prepare_legacy_user_data()
|
||||||
_load_bootstrap_identity()
|
_load_bootstrap_identity()
|
||||||
var command_line: String = _command_line_override()
|
var command_line: String = _command_line_override()
|
||||||
if not command_line.is_empty():
|
if not command_line.is_empty():
|
||||||
override_active = true
|
override_active = true
|
||||||
mode = Mode.COMMAND_LINE_OVERRIDE
|
mode = Mode.COMMAND_LINE_OVERRIDE
|
||||||
return _activate_existing(command_line, "", false)
|
return _activate_existing(command_line, "", false)
|
||||||
if OS.has_environment(ENVIRONMENT_VARIABLE):
|
var environment_variable: String = _available_environment_variable(
|
||||||
|
ENVIRONMENT_VARIABLE,
|
||||||
|
LEGACY_ENVIRONMENT_VARIABLE,
|
||||||
|
)
|
||||||
|
if not environment_variable.is_empty():
|
||||||
override_active = true
|
override_active = true
|
||||||
mode = Mode.ENVIRONMENT_OVERRIDE
|
mode = Mode.ENVIRONMENT_OVERRIDE
|
||||||
var environment_path: String = OS.get_environment(ENVIRONMENT_VARIABLE)
|
var environment_path: String = OS.get_environment(environment_variable)
|
||||||
if not environment_path.is_absolute_path():
|
if not environment_path.is_absolute_path():
|
||||||
return _fail("NETFISHING_DATA_DIR must be an absolute path.")
|
return _fail("straywild_DATA_DIR must be an absolute path.")
|
||||||
if (
|
if (
|
||||||
OS.get_environment(CREATE_ENVIRONMENT_VARIABLE) == "1"
|
_environment_flag(
|
||||||
and not FileAccess.file_exists(
|
CREATE_ENVIRONMENT_VARIABLE,
|
||||||
environment_path.path_join(MANIFEST_FILENAME)
|
LEGACY_CREATE_ENVIRONMENT_VARIABLE,
|
||||||
)
|
)
|
||||||
|
and not has_data_manifest(environment_path)
|
||||||
):
|
):
|
||||||
var created: Dictionary = create_unbound_root(environment_path)
|
var created: Dictionary = create_unbound_root(environment_path)
|
||||||
if not bool(created.get("ok", false)):
|
if not bool(created.get("ok", false)):
|
||||||
|
|
@ -80,11 +116,35 @@ func resolve() -> bool:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func prepare_legacy_user_data() -> void:
|
||||||
|
var current_root: String = _normalize(
|
||||||
|
ProjectSettings.globalize_path("user://")
|
||||||
|
)
|
||||||
|
if current_root.is_empty():
|
||||||
|
return
|
||||||
|
var legacy_root: String = _normalize(
|
||||||
|
current_root.get_base_dir().path_join(LEGACY_USER_DIRECTORY_NAME)
|
||||||
|
)
|
||||||
|
if legacy_root == current_root or not DirAccess.dir_exists_absolute(legacy_root):
|
||||||
|
return
|
||||||
|
for filename: String in LEGACY_USER_FILES:
|
||||||
|
var destination: String = current_root.path_join(filename)
|
||||||
|
if FileAccess.file_exists(destination):
|
||||||
|
continue
|
||||||
|
var source: String = legacy_root.path_join(filename)
|
||||||
|
if FileAccess.file_exists(source):
|
||||||
|
_copy_legacy_user_file(source, destination)
|
||||||
|
|
||||||
|
|
||||||
|
func has_data_manifest(path: String) -> bool:
|
||||||
|
return not _existing_manifest_path(_normalize(path)).is_empty()
|
||||||
|
|
||||||
|
|
||||||
func default_visible_path() -> String:
|
func default_visible_path() -> String:
|
||||||
var documents: String = OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)
|
var documents: String = OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)
|
||||||
if documents.is_empty():
|
if documents.is_empty():
|
||||||
return ""
|
return ""
|
||||||
var candidate: String = _normalize(documents.path_join("NETFISHING"))
|
var candidate: String = _normalize(documents.path_join("straywild"))
|
||||||
if not candidate.is_absolute_path():
|
if not candidate.is_absolute_path():
|
||||||
return ""
|
return ""
|
||||||
var classification: StringName = classify_candidate_path(
|
var classification: StringName = classify_candidate_path(
|
||||||
|
|
@ -105,20 +165,22 @@ func select_new_root(path: String, app_data: bool = false) -> bool:
|
||||||
normalized = ProjectSettings.globalize_path(APP_DATA_PORTABLE_PATH)
|
normalized = ProjectSettings.globalize_path(APP_DATA_PORTABLE_PATH)
|
||||||
if not _validate_candidate(normalized, true):
|
if not _validate_candidate(normalized, true):
|
||||||
return false
|
return false
|
||||||
var manifest_path: String = normalized.path_join(MANIFEST_FILENAME)
|
var manifest_path: String = _existing_manifest_path(normalized)
|
||||||
if FileAccess.file_exists(manifest_path):
|
if not manifest_path.is_empty():
|
||||||
var manifest: Dictionary = _read_json(manifest_path)
|
var manifest: Dictionary = _read_json(manifest_path)
|
||||||
if not _valid_manifest(manifest):
|
if not _valid_manifest(manifest):
|
||||||
return _fail("The selected folder has a malformed NETfishing manifest.")
|
return _fail("The selected folder has a malformed straywild manifest.")
|
||||||
root_id = str(manifest["root_id"])
|
root_id = str(manifest["root_id"])
|
||||||
|
if not _upgrade_legacy_manifest(normalized, manifest, manifest_path):
|
||||||
|
return _fail("The legacy data-folder manifest could not be upgraded.")
|
||||||
else:
|
else:
|
||||||
if not _directory_is_empty(normalized) and not app_data:
|
if not _directory_is_empty(normalized) and not app_data:
|
||||||
return _fail(
|
return _fail(
|
||||||
"Choose an empty folder or an existing NETfishing data folder."
|
"Choose an empty folder or an existing straywild data folder."
|
||||||
)
|
)
|
||||||
root_id = Crypto.new().generate_random_bytes(16).hex_encode()
|
root_id = Crypto.new().generate_random_bytes(16).hex_encode()
|
||||||
if not _create_layout(normalized, root_id):
|
if not _create_layout(normalized, root_id):
|
||||||
return _fail("The NETfishing data folder could not be created.")
|
return _fail("The straywild data folder could not be created.")
|
||||||
if not _write_bootstrap(normalized, root_id):
|
if not _write_bootstrap(normalized, root_id):
|
||||||
return _fail("The data-folder pointer could not be saved.")
|
return _fail("The data-folder pointer could not be saved.")
|
||||||
root_path = normalized
|
root_path = normalized
|
||||||
|
|
@ -145,14 +207,14 @@ func create_app_data_layout_for_migration(path: String) -> Dictionary:
|
||||||
var normalized: String = _normalize(path)
|
var normalized: String = _normalize(path)
|
||||||
if not _validate_candidate(normalized, false):
|
if not _validate_candidate(normalized, false):
|
||||||
return {"ok": false, "message": error_message}
|
return {"ok": false, "message": error_message}
|
||||||
var manifest_path: String = normalized.path_join(MANIFEST_FILENAME)
|
var manifest_path: String = _existing_manifest_path(normalized)
|
||||||
if FileAccess.file_exists(manifest_path):
|
if not manifest_path.is_empty():
|
||||||
var manifest: Dictionary = _read_json(manifest_path)
|
var manifest: Dictionary = _read_json(manifest_path)
|
||||||
return (
|
if not _valid_manifest(manifest):
|
||||||
{"ok": true, "root_id": str(manifest.get("root_id", ""))}
|
return {"ok": false, "message": "The app-data manifest is malformed."}
|
||||||
if _valid_manifest(manifest)
|
if not _upgrade_legacy_manifest(normalized, manifest, manifest_path):
|
||||||
else {"ok": false, "message": "The app-data manifest is malformed."}
|
return {"ok": false, "message": "The app-data manifest could not be upgraded."}
|
||||||
)
|
return {"ok": true, "root_id": str(manifest.get("root_id", ""))}
|
||||||
var id: String = Crypto.new().generate_random_bytes(16).hex_encode()
|
var id: String = Crypto.new().generate_random_bytes(16).hex_encode()
|
||||||
if not _create_layout(normalized, id):
|
if not _create_layout(normalized, id):
|
||||||
return {"ok": false, "message": "The app-data layout could not be created."}
|
return {"ok": false, "message": "The app-data layout could not be created."}
|
||||||
|
|
@ -236,17 +298,19 @@ func _activate_existing(path: String, expected_id: String, permit_creation: bool
|
||||||
var normalized: String = _normalize(path)
|
var normalized: String = _normalize(path)
|
||||||
if not _validate_candidate(normalized, permit_creation):
|
if not _validate_candidate(normalized, permit_creation):
|
||||||
return false
|
return false
|
||||||
var manifest_path: String = normalized.path_join(MANIFEST_FILENAME)
|
var manifest_path: String = _existing_manifest_path(normalized)
|
||||||
if not FileAccess.file_exists(manifest_path):
|
if manifest_path.is_empty():
|
||||||
return _fail("The selected folder is not a NETfishing data folder.")
|
return _fail("The selected folder is not a straywild data folder.")
|
||||||
var manifest: Dictionary = _read_json(manifest_path)
|
var manifest: Dictionary = _read_json(manifest_path)
|
||||||
if not _valid_manifest(manifest):
|
if not _valid_manifest(manifest):
|
||||||
return _fail("The NETfishing data-folder manifest is malformed.")
|
return _fail("The straywild data-folder manifest is malformed.")
|
||||||
|
if not _upgrade_legacy_manifest(normalized, manifest, manifest_path):
|
||||||
|
return _fail("The legacy data-folder manifest could not be upgraded.")
|
||||||
var found_id: String = str(manifest["root_id"])
|
var found_id: String = str(manifest["root_id"])
|
||||||
if not expected_id.is_empty() and expected_id != found_id:
|
if not expected_id.is_empty() and expected_id != found_id:
|
||||||
return _fail("The selected data folder does not match this device pointer.")
|
return _fail("The selected data folder does not match this device pointer.")
|
||||||
if not _test_writable(normalized):
|
if not _test_writable(normalized):
|
||||||
return _fail("The NETfishing data folder is unavailable or unwritable.")
|
return _fail("The straywild data folder is unavailable or unwritable.")
|
||||||
root_path = normalized
|
root_path = normalized
|
||||||
root_id = found_id
|
root_id = found_id
|
||||||
requires_selection = false
|
requires_selection = false
|
||||||
|
|
@ -339,7 +403,7 @@ static func _is_same_or_child_path(candidate: String, reference: String) -> bool
|
||||||
|
|
||||||
func _test_writable(path: String) -> bool:
|
func _test_writable(path: String) -> bool:
|
||||||
var probe: String = path.path_join(
|
var probe: String = path.path_join(
|
||||||
".netfishing-write-%s.tmp" % device_id.left(12)
|
".straywild-write-%s.tmp" % device_id.left(12)
|
||||||
)
|
)
|
||||||
var file: FileAccess = FileAccess.open(probe, FileAccess.WRITE)
|
var file: FileAccess = FileAccess.open(probe, FileAccess.WRITE)
|
||||||
if file == null:
|
if file == null:
|
||||||
|
|
@ -370,7 +434,7 @@ func _create_layout(path: String, id: String) -> bool:
|
||||||
):
|
):
|
||||||
return false
|
return false
|
||||||
var readme: String = (
|
var readme: String = (
|
||||||
"NETfishing player data\n\n"
|
"straywild player data\n\n"
|
||||||
+ "This folder is safe to synchronize with tools such as Syncthing.\n"
|
+ "This folder is safe to synchronize with tools such as Syncthing.\n"
|
||||||
+ "Active private identity keys remain device-local.\n"
|
+ "Active private identity keys remain device-local.\n"
|
||||||
+ "Encrypted identity backups require their passphrase.\n"
|
+ "Encrypted identity backups require their passphrase.\n"
|
||||||
|
|
@ -422,12 +486,71 @@ func _valid_manifest(data: Dictionary) -> bool:
|
||||||
return (
|
return (
|
||||||
data.get("format_version") == MANIFEST_VERSION
|
data.get("format_version") == MANIFEST_VERSION
|
||||||
and data.get("layout_version") == LAYOUT_VERSION
|
and data.get("layout_version") == LAYOUT_VERSION
|
||||||
and data.get("application") == APPLICATION_ID
|
and data.get("application") in [APPLICATION_ID, LEGACY_APPLICATION_ID]
|
||||||
and typeof(data.get("root_id")) == TYPE_STRING
|
and typeof(data.get("root_id")) == TYPE_STRING
|
||||||
and str(data["root_id"]).length() == 32
|
and str(data["root_id"]).length() == 32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _existing_manifest_path(path: String) -> String:
|
||||||
|
var current: String = path.path_join(MANIFEST_FILENAME)
|
||||||
|
if FileAccess.file_exists(current):
|
||||||
|
return current
|
||||||
|
var legacy: String = path.path_join(LEGACY_MANIFEST_FILENAME)
|
||||||
|
return legacy if FileAccess.file_exists(legacy) else ""
|
||||||
|
|
||||||
|
|
||||||
|
func _upgrade_legacy_manifest(
|
||||||
|
path: String,
|
||||||
|
manifest: Dictionary,
|
||||||
|
manifest_path: String,
|
||||||
|
) -> bool:
|
||||||
|
if (
|
||||||
|
manifest_path.get_file() == MANIFEST_FILENAME
|
||||||
|
and manifest.get("application") == APPLICATION_ID
|
||||||
|
):
|
||||||
|
return true
|
||||||
|
var upgraded: Dictionary = manifest.duplicate(true)
|
||||||
|
upgraded["application"] = APPLICATION_ID
|
||||||
|
upgraded["last_opened_at_unix"] = int(Time.get_unix_time_from_system())
|
||||||
|
return _write_text_atomic(
|
||||||
|
path.path_join(MANIFEST_FILENAME),
|
||||||
|
JSON.stringify(upgraded, "\t"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _available_environment_variable(primary: String, legacy: String) -> String:
|
||||||
|
if OS.has_environment(primary):
|
||||||
|
return primary
|
||||||
|
return legacy if OS.has_environment(legacy) else ""
|
||||||
|
|
||||||
|
|
||||||
|
func _environment_flag(primary: String, legacy: String) -> bool:
|
||||||
|
var variable: String = _available_environment_variable(primary, legacy)
|
||||||
|
return not variable.is_empty() and OS.get_environment(variable) == "1"
|
||||||
|
|
||||||
|
|
||||||
|
func _copy_legacy_user_file(source: String, destination: String) -> bool:
|
||||||
|
var bytes: PackedByteArray = PortableFileGuard.read_bytes(
|
||||||
|
source,
|
||||||
|
16 * 1024 * 1024,
|
||||||
|
)
|
||||||
|
if bytes.is_empty() and FileAccess.get_open_error() != OK:
|
||||||
|
return false
|
||||||
|
if DirAccess.make_dir_recursive_absolute(destination.get_base_dir()) != OK:
|
||||||
|
return false
|
||||||
|
var file: FileAccess = FileAccess.open(destination, FileAccess.WRITE)
|
||||||
|
if file == null:
|
||||||
|
return false
|
||||||
|
file.store_buffer(bytes)
|
||||||
|
file.flush()
|
||||||
|
var copied: bool = file.get_error() == OK
|
||||||
|
file.close()
|
||||||
|
if copied and source.ends_with(".key"):
|
||||||
|
FileAccess.set_unix_permissions(destination, 384)
|
||||||
|
return copied
|
||||||
|
|
||||||
|
|
||||||
func _directory_is_empty(path: String) -> bool:
|
func _directory_is_empty(path: String) -> bool:
|
||||||
var access: DirAccess = DirAccess.open(path)
|
var access: DirAccess = DirAccess.open(path)
|
||||||
if access == null:
|
if access == null:
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ const FORMAT_VERSION := 2
|
||||||
const MAX_RECORDS := 500
|
const MAX_RECORDS := 500
|
||||||
const MAX_FRIENDS := 200
|
const MAX_FRIENDS := 200
|
||||||
const SOCIAL_TOKEN_LENGTH := 64
|
const SOCIAL_TOKEN_LENGTH := 64
|
||||||
const PRESENCE_CHANNEL_DOMAIN := "NETFISHING_PRESENCE_V1:"
|
const PRESENCE_CHANNEL_DOMAIN := "straywild_PRESENCE_V1:"
|
||||||
const INVITE_INBOX_DOMAIN := "NETFISHING_INVITE_V1:"
|
const INVITE_INBOX_DOMAIN := "straywild_INVITE_V1:"
|
||||||
|
|
||||||
var _records: Dictionary = {}
|
var _records: Dictionary = {}
|
||||||
var _loaded := false
|
var _loaded := false
|
||||||
|
|
@ -21,6 +21,10 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_store_path = path
|
_store_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_records.clear()
|
||||||
|
_loaded = false
|
||||||
|
_write_blocked = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func is_muted(fingerprint: String) -> bool:
|
func is_muted(fingerprint: String) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,16 @@ static func migrate_legacy_to(
|
||||||
) -> Dictionary:
|
) -> Dictionary:
|
||||||
var normalized: String = destination.simplify_path().trim_suffix("/")
|
var normalized: String = destination.simplify_path().trim_suffix("/")
|
||||||
if DirAccess.dir_exists_absolute(normalized):
|
if DirAccess.dir_exists_absolute(normalized):
|
||||||
var existing_manifest: String = normalized.path_join(
|
if data_root.has_data_manifest(normalized):
|
||||||
PlayerDataRoot.MANIFEST_FILENAME
|
|
||||||
)
|
|
||||||
if FileAccess.file_exists(existing_manifest):
|
|
||||||
return {
|
return {
|
||||||
"ok": false,
|
"ok": false,
|
||||||
"requires_existing_root_decision": true,
|
"requires_existing_root_decision": true,
|
||||||
"message": "The selected folder already contains NETfishing data.",
|
"message": "The selected folder already contains straywild data.",
|
||||||
}
|
}
|
||||||
if not _directory_empty(normalized):
|
if not _directory_empty(normalized):
|
||||||
return {
|
return {
|
||||||
"ok": false,
|
"ok": false,
|
||||||
"message": "Choose an empty folder or create a NETfishing subfolder.",
|
"message": "Choose an empty folder or create a straywild subfolder.",
|
||||||
}
|
}
|
||||||
var staging: String = "%s.migration-%s" % [
|
var staging: String = "%s.migration-%s" % [
|
||||||
normalized, Crypto.new().generate_random_bytes(8).hex_encode()
|
normalized, Crypto.new().generate_random_bytes(8).hex_encode()
|
||||||
|
|
@ -106,16 +103,16 @@ static func migrate_active_to(
|
||||||
"message": "This data folder is already active.",
|
"message": "This data folder is already active.",
|
||||||
}
|
}
|
||||||
if DirAccess.dir_exists_absolute(normalized) and not _directory_empty(normalized):
|
if DirAccess.dir_exists_absolute(normalized) and not _directory_empty(normalized):
|
||||||
if FileAccess.file_exists(normalized.path_join(PlayerDataRoot.MANIFEST_FILENAME)):
|
if data_root.has_data_manifest(normalized):
|
||||||
return {
|
return {
|
||||||
"ok": false,
|
"ok": false,
|
||||||
"requires_existing_root_decision": true,
|
"requires_existing_root_decision": true,
|
||||||
"message": (
|
"message": (
|
||||||
"The selected folder already contains NETfishing data. "
|
"The selected folder already contains straywild data. "
|
||||||
+ "Choose it through the existing-data recovery flow."
|
+ "Choose it through the existing-data recovery flow."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
return {"ok": false, "message": "Choose an empty folder or a NETfishing subfolder."}
|
return {"ok": false, "message": "Choose an empty folder or a straywild subfolder."}
|
||||||
var staging: String = "%s.migration-%s" % [
|
var staging: String = "%s.migration-%s" % [
|
||||||
normalized, Crypto.new().generate_random_bytes(8).hex_encode()
|
normalized, Crypto.new().generate_random_bytes(8).hex_encode()
|
||||||
]
|
]
|
||||||
|
|
@ -207,9 +204,8 @@ static func replace_existing_with_legacy(
|
||||||
destination: String,
|
destination: String,
|
||||||
) -> Dictionary:
|
) -> Dictionary:
|
||||||
var normalized: String = destination.simplify_path().trim_suffix("/")
|
var normalized: String = destination.simplify_path().trim_suffix("/")
|
||||||
var manifest: String = normalized.path_join(PlayerDataRoot.MANIFEST_FILENAME)
|
if not data_root.has_data_manifest(normalized):
|
||||||
if not FileAccess.file_exists(manifest):
|
return {"ok": false, "message": "The selected folder is not a straywild data root."}
|
||||||
return {"ok": false, "message": "The selected folder is not a NETfishing data root."}
|
|
||||||
var recovery: String = ProjectSettings.globalize_path(
|
var recovery: String = ProjectSettings.globalize_path(
|
||||||
"user://migration-recovery"
|
"user://migration-recovery"
|
||||||
).path_join(
|
).path_join(
|
||||||
|
|
@ -229,8 +225,8 @@ static func replace_existing_with_active(
|
||||||
destination: String,
|
destination: String,
|
||||||
) -> Dictionary:
|
) -> Dictionary:
|
||||||
var normalized: String = destination.simplify_path().trim_suffix("/")
|
var normalized: String = destination.simplify_path().trim_suffix("/")
|
||||||
if not FileAccess.file_exists(normalized.path_join(PlayerDataRoot.MANIFEST_FILENAME)):
|
if not data_root.has_data_manifest(normalized):
|
||||||
return {"ok": false, "message": "The selected folder is not a NETfishing data root."}
|
return {"ok": false, "message": "The selected folder is not a straywild data root."}
|
||||||
var recovery: String = ProjectSettings.globalize_path(
|
var recovery: String = ProjectSettings.globalize_path(
|
||||||
"user://migration-recovery"
|
"user://migration-recovery"
|
||||||
).path_join(
|
).path_join(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,12 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_store_path = path
|
_store_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_saved_entries.clear()
|
||||||
|
_recent_entries.clear()
|
||||||
|
_loaded = false
|
||||||
|
_recovery_warning = ""
|
||||||
|
_write_blocked = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func _temp_path() -> String:
|
func _temp_path() -> String:
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_store_path = path
|
_store_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_records.clear()
|
||||||
|
_loaded = false
|
||||||
|
_write_blocked = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func verify(endpoint: ConnectionEndpoint, fingerprint: String) -> Verification:
|
func verify(endpoint: ConnectionEndpoint, fingerprint: String) -> Verification:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,88 @@
|
||||||
extends "res://player/tool_socket_attachment.gd"
|
extends "res://player/tool_socket_attachment.gd"
|
||||||
|
|
||||||
@onready var _impact_marker: Marker3D = %ImpactMarker
|
const TextureSamplingPolicyScript := preload(
|
||||||
|
"res://main/texture_sampling_policy.gd"
|
||||||
|
)
|
||||||
|
const SPRING_ROOT_BONE: StringName = &"net_mid"
|
||||||
|
const SPRING_END_BONE: StringName = &"net_tip"
|
||||||
|
const IMPACT_BONE: StringName = &"net_rim"
|
||||||
|
|
||||||
|
@export_range(0.0, 10.0, 0.05) var spring_stiffness: float = 1.8
|
||||||
|
@export_range(0.0, 1.0, 0.01) var spring_drag: float = 0.68
|
||||||
|
@export_range(0.0, 10.0, 0.05) var spring_gravity: float = 0.3
|
||||||
|
@export_range(0.01, 0.5, 0.01) var spring_end_length: float = 0.1
|
||||||
|
|
||||||
|
@onready var _catching_net: Node3D = %CatchingNet
|
||||||
|
@onready var _net_model: Node3D = %NetModel
|
||||||
|
|
||||||
|
var _spring: SpringBoneSimulator3D
|
||||||
|
var _spring_was_visible: bool = false
|
||||||
|
var _net_skeleton: Skeleton3D
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
super._ready()
|
||||||
|
TextureSamplingPolicyScript.enforce_subtree(_net_model)
|
||||||
|
_configure_spring()
|
||||||
|
_sync_spring_activity()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
_sync_spring_activity()
|
||||||
|
|
||||||
|
|
||||||
|
func _configure_spring() -> void:
|
||||||
|
_net_skeleton = _net_model.find_child(
|
||||||
|
"Skeleton3D", true, false
|
||||||
|
) as Skeleton3D
|
||||||
|
if _net_skeleton == null:
|
||||||
|
push_error("Imported net model is missing its Skeleton3D.")
|
||||||
|
return
|
||||||
|
if _net_skeleton.find_bone(SPRING_ROOT_BONE) < 0:
|
||||||
|
push_error("Imported net model is missing bone %s." % SPRING_ROOT_BONE)
|
||||||
|
return
|
||||||
|
if _net_skeleton.find_bone(SPRING_END_BONE) < 0:
|
||||||
|
push_error("Imported net model is missing bone %s." % SPRING_END_BONE)
|
||||||
|
return
|
||||||
|
if _net_skeleton.find_bone(IMPACT_BONE) < 0:
|
||||||
|
push_error("Imported net model is missing bone %s." % IMPACT_BONE)
|
||||||
|
return
|
||||||
|
|
||||||
|
_spring = SpringBoneSimulator3D.new()
|
||||||
|
_spring.name = "NetSpring"
|
||||||
|
_spring.set_setting_count(1)
|
||||||
|
_spring.set_root_bone_name(0, SPRING_ROOT_BONE)
|
||||||
|
_spring.set_end_bone_name(0, SPRING_END_BONE)
|
||||||
|
_spring.set_extend_end_bone(0, true)
|
||||||
|
_spring.set_end_bone_direction(
|
||||||
|
0, SkeletonModifier3D.BONE_DIRECTION_FROM_PARENT
|
||||||
|
)
|
||||||
|
_spring.set_end_bone_length(0, spring_end_length)
|
||||||
|
_spring.set_stiffness(0, spring_stiffness)
|
||||||
|
_spring.set_drag(0, spring_drag)
|
||||||
|
_spring.set_gravity(0, spring_gravity)
|
||||||
|
_spring.set_gravity_direction(0, Vector3.DOWN)
|
||||||
|
_net_skeleton.add_child(_spring)
|
||||||
|
|
||||||
|
|
||||||
func get_impact_world_position() -> Vector3:
|
func get_impact_world_position() -> Vector3:
|
||||||
return _impact_marker.global_position
|
if _net_skeleton == null:
|
||||||
|
return _catching_net.global_position
|
||||||
|
var impact_bone_index := _net_skeleton.find_bone(IMPACT_BONE)
|
||||||
|
if impact_bone_index < 0:
|
||||||
|
return _catching_net.global_position
|
||||||
|
return _net_skeleton.global_transform * (
|
||||||
|
_net_skeleton.get_bone_global_pose(impact_bone_index).origin
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _sync_spring_activity() -> void:
|
||||||
|
if _spring == null:
|
||||||
|
return
|
||||||
|
var is_visible := _catching_net.is_visible_in_tree()
|
||||||
|
if is_visible and not _spring_was_visible:
|
||||||
|
_spring.active = true
|
||||||
|
_spring.reset()
|
||||||
|
elif not is_visible:
|
||||||
|
_spring.active = false
|
||||||
|
_spring_was_visible = is_visible
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,7 @@
|
||||||
[gd_scene load_steps=8 format=3]
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://player/net_attachment.gd" id="1_script"]
|
[ext_resource type="Script" path="res://player/net_attachment.gd" id="1_script"]
|
||||||
|
[ext_resource type="PackedScene" path="res://art/exported/items/equipment/net.glb" id="2_model"]
|
||||||
[sub_resource type="StandardMaterial3D" id="HandleMaterial"]
|
|
||||||
albedo_color = Color(0.25, 0.13, 0.055, 1)
|
|
||||||
roughness = 0.9
|
|
||||||
|
|
||||||
[sub_resource type="CylinderMesh" id="HandleMesh"]
|
|
||||||
material = SubResource("HandleMaterial")
|
|
||||||
top_radius = 0.025
|
|
||||||
bottom_radius = 0.035
|
|
||||||
height = 1.25
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="HoopMaterial"]
|
|
||||||
albedo_color = Color(0.34, 0.39, 0.4, 1)
|
|
||||||
metallic = 0.25
|
|
||||||
roughness = 0.65
|
|
||||||
|
|
||||||
[sub_resource type="TorusMesh" id="HoopMesh"]
|
|
||||||
material = SubResource("HoopMaterial")
|
|
||||||
inner_radius = 0.24
|
|
||||||
outer_radius = 0.29
|
|
||||||
rings = 12
|
|
||||||
ring_segments = 18
|
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="NetMaterial"]
|
|
||||||
transparency = 1
|
|
||||||
albedo_color = Color(0.65, 0.78, 0.75, 0.42)
|
|
||||||
shading_mode = 0
|
|
||||||
cull_mode = 2
|
|
||||||
|
|
||||||
[sub_resource type="CylinderMesh" id="NetMesh"]
|
|
||||||
material = SubResource("NetMaterial")
|
|
||||||
top_radius = 0.24
|
|
||||||
bottom_radius = 0.08
|
|
||||||
height = 0.34
|
|
||||||
radial_segments = 12
|
|
||||||
rings = 1
|
|
||||||
|
|
||||||
[node name="NetAttachment" type="BoneAttachment3D"]
|
[node name="NetAttachment" type="BoneAttachment3D"]
|
||||||
bone_name = "rod_socket"
|
bone_name = "rod_socket"
|
||||||
|
|
@ -47,18 +12,9 @@ aligned_mount_path = NodePath("CatchingNet")
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
[node name="Handle" type="MeshInstance3D" parent="CatchingNet"]
|
[node name="ModelMount" type="Node3D" parent="CatchingNet"]
|
||||||
position = Vector3(0, 0.55, 0)
|
position = Vector3(-0.000217, -0.098636, -0.020218)
|
||||||
mesh = SubResource("HandleMesh")
|
rotation = Vector3(0, 3.1415927, 0)
|
||||||
|
|
||||||
[node name="Hoop" type="MeshInstance3D" parent="CatchingNet"]
|
[node name="NetModel" parent="CatchingNet/ModelMount" unique_id=1627767240 instance=ExtResource("2_model")]
|
||||||
position = Vector3(0, 1.17, 0)
|
|
||||||
mesh = SubResource("HoopMesh")
|
|
||||||
|
|
||||||
[node name="Bag" type="MeshInstance3D" parent="CatchingNet"]
|
|
||||||
position = Vector3(0, 1, 0)
|
|
||||||
mesh = SubResource("NetMesh")
|
|
||||||
|
|
||||||
[node name="ImpactMarker" type="Marker3D" parent="CatchingNet"]
|
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
position = Vector3(0, 1.17, 0)
|
|
||||||
|
|
|
||||||
|
|
@ -1036,6 +1036,8 @@ func _simulate_movement_physics(delta: float) -> void:
|
||||||
or (_network_authoritative_simulation and _network_jump_pending)
|
or (_network_authoritative_simulation and _network_jump_pending)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if jump_requested:
|
||||||
|
_cancel_sitting_for_jump()
|
||||||
# Sitting deliberately stops movement processing, so never allow a stale
|
# Sitting deliberately stops movement processing, so never allow a stale
|
||||||
# grounded flag or a reconciled network state to leave an airborne avatar in
|
# grounded flag or a reconciled network state to leave an airborne avatar in
|
||||||
# that early-return path. Preserve the intent and sit once landing is real.
|
# that early-return path. Preserve the intent and sit once landing is real.
|
||||||
|
|
@ -1635,6 +1637,7 @@ func _complete_retract_animation() -> void:
|
||||||
func toggle_sitting() -> void:
|
func toggle_sitting() -> void:
|
||||||
if _sit_after_landing:
|
if _sit_after_landing:
|
||||||
_sit_after_landing = false
|
_sit_after_landing = false
|
||||||
|
_set_sitting(false, local_control_enabled)
|
||||||
return
|
return
|
||||||
var should_sit: bool = not _sitting
|
var should_sit: bool = not _sitting
|
||||||
if should_sit:
|
if should_sit:
|
||||||
|
|
@ -1667,12 +1670,12 @@ func _set_sitting(
|
||||||
should_sit: bool,
|
should_sit: bool,
|
||||||
is_local_intent: bool = false,
|
is_local_intent: bool = false,
|
||||||
) -> void:
|
) -> void:
|
||||||
if _sitting == should_sit:
|
|
||||||
return
|
|
||||||
_sitting = should_sit
|
|
||||||
if is_local_intent:
|
if is_local_intent:
|
||||||
_sitting_intent_pending = true
|
_sitting_intent_pending = true
|
||||||
_sitting_intent_sequence = -1
|
_sitting_intent_sequence = -1
|
||||||
|
if _sitting == should_sit:
|
||||||
|
return
|
||||||
|
_sitting = should_sit
|
||||||
if _sitting:
|
if _sitting:
|
||||||
velocity = Vector3.ZERO
|
velocity = Vector3.ZERO
|
||||||
_character_animation_name = &""
|
_character_animation_name = &""
|
||||||
|
|
@ -1687,11 +1690,23 @@ func _can_begin_sitting() -> bool:
|
||||||
return is_on_floor() and velocity.y <= 0.0
|
return is_on_floor() and velocity.y <= 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _cancel_sitting_for_jump() -> void:
|
||||||
|
if not _sitting and not _sit_after_landing:
|
||||||
|
return
|
||||||
|
_sit_after_landing = false
|
||||||
|
_set_sitting(false, local_control_enabled)
|
||||||
|
|
||||||
|
|
||||||
func get_network_sitting_state() -> bool:
|
func get_network_sitting_state() -> bool:
|
||||||
return _sitting
|
return _sitting
|
||||||
|
|
||||||
|
|
||||||
func get_network_sitting_intent() -> bool:
|
func get_network_sitting_intent() -> bool:
|
||||||
|
# Jumping is an explicit cancellation of both a current sit and a deferred
|
||||||
|
# sit. Input capture can run before the matching physics frame, so suppress
|
||||||
|
# the stale seated bit as soon as the reliable jump intent is queued.
|
||||||
|
if _local_network_jump_intent_pending:
|
||||||
|
return false
|
||||||
return _sitting or _sit_after_landing
|
return _sitting or _sit_after_landing
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2352,6 +2367,21 @@ func apply_local_prediction_correction(
|
||||||
_local_prediction_hard_corrections += 1
|
_local_prediction_hard_corrections += 1
|
||||||
_reset_local_prediction_error()
|
_reset_local_prediction_error()
|
||||||
return
|
return
|
||||||
|
if _should_defer_local_prediction_correction(parsed):
|
||||||
|
# A host and its client do not reach the apex or landing on the same
|
||||||
|
# frame. Correcting that expected vertical disagreement while either
|
||||||
|
# side is airborne can pull the local body off narrow platforms.
|
||||||
|
_reset_local_prediction_error()
|
||||||
|
return
|
||||||
|
# Both simulations agree the player is standing. Let ordinary floor motion
|
||||||
|
# and gravity resolve the vertical component; a stale height sample must not
|
||||||
|
# press a locally controlled player down or turn a horizontal correction
|
||||||
|
# into an early floor collision.
|
||||||
|
error_offset.y = 0.0
|
||||||
|
error_distance = error_offset.length()
|
||||||
|
if error_distance <= LOCAL_PREDICTION_CORRECTION_THRESHOLD:
|
||||||
|
_reset_local_prediction_error()
|
||||||
|
return
|
||||||
var error_direction: Vector3 = error_offset.normalized()
|
var error_direction: Vector3 = error_offset.normalized()
|
||||||
if (
|
if (
|
||||||
not _local_prediction_error_direction.is_zero_approx()
|
not _local_prediction_error_direction.is_zero_approx()
|
||||||
|
|
@ -2386,22 +2416,34 @@ func apply_local_prediction_correction(
|
||||||
correction.normalized()
|
correction.normalized()
|
||||||
* LOCAL_PREDICTION_MAX_SOFT_CORRECTION_STEP
|
* LOCAL_PREDICTION_MAX_SOFT_CORRECTION_STEP
|
||||||
)
|
)
|
||||||
_apply_camera_safe_local_correction(correction)
|
if _apply_camera_safe_local_correction(correction):
|
||||||
_local_prediction_soft_corrections += 1
|
_local_prediction_soft_corrections += 1
|
||||||
|
|
||||||
|
|
||||||
func _apply_camera_safe_local_correction(correction: Vector3) -> void:
|
func _should_defer_local_prediction_correction(parsed: Dictionary) -> bool:
|
||||||
|
if not bool(parsed.get("grounded", true)):
|
||||||
|
return true
|
||||||
|
return _local_network_jump_intent_pending or not is_on_floor()
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_camera_safe_local_correction(correction: Vector3) -> bool:
|
||||||
if correction.is_zero_approx():
|
if correction.is_zero_approx():
|
||||||
return
|
return false
|
||||||
var previous_visual_position: Vector3 = _visuals.global_position
|
var previous_visual_position: Vector3 = _visuals.global_position
|
||||||
var previous_camera_position: Vector3 = _camera_yaw.global_position
|
var previous_camera_position: Vector3 = _camera_yaw.global_position
|
||||||
|
var previous_body_position: Vector3 = global_position
|
||||||
var base_visual_local_position: Vector3 = (
|
var base_visual_local_position: Vector3 = (
|
||||||
_visuals.position - _local_reconciliation_visual_offset
|
_visuals.position - _local_reconciliation_visual_offset
|
||||||
)
|
)
|
||||||
var base_camera_local_position: Vector3 = (
|
var base_camera_local_position: Vector3 = (
|
||||||
_camera_yaw.position - _local_reconciliation_camera_offset
|
_camera_yaw.position - _local_reconciliation_camera_offset
|
||||||
)
|
)
|
||||||
global_position += correction
|
# Reconciliation is still physical movement. Going through the physics
|
||||||
|
# server prevents a delayed host audit from placing the capsule through a
|
||||||
|
# tree, cliff, or stepping stone on the way to the authoritative position.
|
||||||
|
move_and_collide(correction)
|
||||||
|
if global_position.is_equal_approx(previous_body_position):
|
||||||
|
return false
|
||||||
_visuals.global_position = previous_visual_position
|
_visuals.global_position = previous_visual_position
|
||||||
_camera_yaw.global_position = previous_camera_position
|
_camera_yaw.global_position = previous_camera_position
|
||||||
_local_reconciliation_visual_offset = (
|
_local_reconciliation_visual_offset = (
|
||||||
|
|
@ -2410,6 +2452,7 @@ func _apply_camera_safe_local_correction(correction: Vector3) -> void:
|
||||||
_local_reconciliation_camera_offset = (
|
_local_reconciliation_camera_offset = (
|
||||||
_camera_yaw.position - base_camera_local_position
|
_camera_yaw.position - base_camera_local_position
|
||||||
)
|
)
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
func _reset_local_prediction_error() -> void:
|
func _reset_local_prediction_error() -> void:
|
||||||
|
|
@ -2625,6 +2668,9 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
||||||
if snapshot.has("casting") and typeof(snapshot.get("casting")) != TYPE_BOOL:
|
if snapshot.has("casting") and typeof(snapshot.get("casting")) != TYPE_BOOL:
|
||||||
return {}
|
return {}
|
||||||
var casting: bool = bool(snapshot.get("casting", false))
|
var casting: bool = bool(snapshot.get("casting", false))
|
||||||
|
if snapshot.has("grounded") and typeof(snapshot.get("grounded")) != TYPE_BOOL:
|
||||||
|
return {}
|
||||||
|
var grounded: bool = bool(snapshot.get("grounded", true))
|
||||||
if (
|
if (
|
||||||
not parsed_position.is_finite()
|
not parsed_position.is_finite()
|
||||||
or not parsed_velocity.is_finite()
|
or not parsed_velocity.is_finite()
|
||||||
|
|
@ -2636,6 +2682,7 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary:
|
||||||
"velocity": parsed_velocity,
|
"velocity": parsed_velocity,
|
||||||
"visual_yaw": visual_yaw,
|
"visual_yaw": visual_yaw,
|
||||||
"animation_state": animation_state,
|
"animation_state": animation_state,
|
||||||
|
"grounded": grounded,
|
||||||
"acknowledged_input": acknowledged_input,
|
"acknowledged_input": acknowledged_input,
|
||||||
"sitting": sitting,
|
"sitting": sitting,
|
||||||
"casting": casting,
|
"casting": casting,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
[ext_resource type="Script" path="res://progression/player_cooler_capacity.gd" id="10_capacity"]
|
[ext_resource type="Script" path="res://progression/player_cooler_capacity.gd" id="10_capacity"]
|
||||||
[ext_resource type="Script" path="res://player/player_ground_shadow.gd" id="11_ground_shadow"]
|
[ext_resource type="Script" path="res://player/player_ground_shadow.gd" id="11_ground_shadow"]
|
||||||
[ext_resource type="Material" path="res://player/materials/player_blob_shadow.tres" id="12_blob_shadow"]
|
[ext_resource type="Material" path="res://player/materials/player_blob_shadow.tres" id="12_blob_shadow"]
|
||||||
[ext_resource type="PackedScene" path="res://art/exported/characters/base/netfishing_base_character.glb" id="13_character"]
|
[ext_resource type="PackedScene" path="res://art/exported/characters/base/straywild_base_character.glb" id="13_character"]
|
||||||
[ext_resource type="Script" path="res://progression/player_art_unlocks.gd" id="14_art_unlocks"]
|
[ext_resource type="Script" path="res://progression/player_art_unlocks.gd" id="14_art_unlocks"]
|
||||||
[ext_resource type="Script" path="res://progression/player_experience.gd" id="15_experience"]
|
[ext_resource type="Script" path="res://progression/player_experience.gd" id="15_experience"]
|
||||||
[ext_resource type="Script" path="res://player/sprint_dust_trail.gd" id="16_sprint_dust"]
|
[ext_resource type="Script" path="res://player/sprint_dust_trail.gd" id="16_sprint_dust"]
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ extends RefCounted
|
||||||
|
|
||||||
const PlayerScene: PackedScene = preload("res://player/player.tscn")
|
const PlayerScene: PackedScene = preload("res://player/player.tscn")
|
||||||
const FurPatternShader: Shader = preload("res://player/fur_pattern.gdshader")
|
const FurPatternShader: Shader = preload("res://player/fur_pattern.gdshader")
|
||||||
const RUNTIME_MATERIAL_META: StringName = &"netfishing_runtime_material"
|
const RUNTIME_MATERIAL_META: StringName = &"straywild_runtime_material"
|
||||||
const RUNTIME_FUR_PATTERN_MATERIAL_META: StringName = (
|
const RUNTIME_FUR_PATTERN_MATERIAL_META: StringName = (
|
||||||
&"netfishing_runtime_fur_pattern_material"
|
&"straywild_runtime_fur_pattern_material"
|
||||||
)
|
)
|
||||||
const EAR_MESH_NAMES: Array[String] = [
|
const EAR_MESH_NAMES: Array[String] = [
|
||||||
"ears_antlers_round",
|
"ears_antlers_round",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ var _data_root: PlayerDataRoot
|
||||||
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
func configure_storage(path: String, data_root: PlayerDataRoot) -> void:
|
||||||
_profile_path = path
|
_profile_path = path
|
||||||
_data_root = data_root
|
_data_root = data_root
|
||||||
|
_snapshot = CharacterCustomizationCatalog.default_snapshot()
|
||||||
|
_loaded = false
|
||||||
|
_future_version = false
|
||||||
|
_expected_hash = ""
|
||||||
|
|
||||||
|
|
||||||
func _temp_path() -> String:
|
func _temp_path() -> String:
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ config_version=5
|
||||||
|
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="NETFISHING"
|
config/name="straywild"
|
||||||
config/version="0.18.0-alpha"
|
config/version="0.19.0-alpha"
|
||||||
run/main_scene="res://main/main.tscn"
|
run/main_scene="res://main/main.tscn"
|
||||||
config/features=PackedStringArray("4.7", "GL Compatibility")
|
config/features=PackedStringArray("4.7", "GL Compatibility")
|
||||||
config/icon="res://art/exported/system_icons/netfishing_256.png"
|
config/icon="res://art/exported/system_icons/straywild_256.png"
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ window/stretch/aspect="expand"
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PackedStringArray("res://addons/netfishing_shoreline_baker/plugin.cfg")
|
enabled=PackedStringArray("res://addons/straywild_shoreline_baker/plugin.cfg")
|
||||||
|
|
||||||
[gui]
|
[gui]
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ alternate_fishing={
|
||||||
|
|
||||||
[network]
|
[network]
|
||||||
|
|
||||||
discovery/base_url="https://discovery.netfishing.org"
|
discovery/base_url="https://discovery.straywild.io"
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
class_name ProgressionSaveCodec
|
class_name ProgressionSaveCodec
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
const MAGIC := "NETFISHING_PROGRESSION_CONTAINER"
|
const MAGIC := "straywild_PROGRESSION_CONTAINER"
|
||||||
|
const LEGACY_MAGIC := "NETFISHING_PROGRESSION_CONTAINER"
|
||||||
const FORMAT_VERSION := 1
|
const FORMAT_VERSION := 1
|
||||||
const LOCAL_KIND := "local_save"
|
const LOCAL_KIND := "local_save"
|
||||||
const ARCHIVE_KIND := "portable_archive"
|
const ARCHIVE_KIND := "portable_archive"
|
||||||
|
|
@ -9,6 +10,8 @@ const MAX_CONTAINER_BYTES := 16 * 1024 * 1024
|
||||||
|
|
||||||
# This key keeps routine progression files opaque to casual editing. Since the
|
# This key keeps routine progression files opaque to casual editing. Since the
|
||||||
# client is open source, it is intentionally not treated as a security secret.
|
# client is open source, it is intentionally not treated as a security secret.
|
||||||
|
# Its original value is a stable file-format detail so released saves remain
|
||||||
|
# readable after the Straywild rebrand.
|
||||||
const CONTAINER_PASSPHRASE := (
|
const CONTAINER_PASSPHRASE := (
|
||||||
"NETfishing progression container v1 / not an identity credential"
|
"NETfishing progression container v1 / not an identity credential"
|
||||||
)
|
)
|
||||||
|
|
@ -102,15 +105,9 @@ static func _read_container(path: String, expected_kind: String) -> Dictionary:
|
||||||
or FileAccess.get_size(path) > MAX_CONTAINER_BYTES
|
or FileAccess.get_size(path) > MAX_CONTAINER_BYTES
|
||||||
):
|
):
|
||||||
return {"ok": false, "message": "progression file is unavailable."}
|
return {"ok": false, "message": "progression file is unavailable."}
|
||||||
var file: FileAccess = FileAccess.open_encrypted_with_pass(
|
var envelope_text: String = _read_encrypted_text(path)
|
||||||
path,
|
if envelope_text.is_empty():
|
||||||
FileAccess.READ,
|
|
||||||
CONTAINER_PASSPHRASE,
|
|
||||||
)
|
|
||||||
if file == null:
|
|
||||||
return {"ok": false, "message": "progression file could not be opened."}
|
return {"ok": false, "message": "progression file could not be opened."}
|
||||||
var envelope_text: String = file.get_as_text()
|
|
||||||
file.close()
|
|
||||||
var envelope_json := JSON.new()
|
var envelope_json := JSON.new()
|
||||||
if (
|
if (
|
||||||
envelope_json.parse(envelope_text) != OK
|
envelope_json.parse(envelope_text) != OK
|
||||||
|
|
@ -118,8 +115,9 @@ static func _read_container(path: String, expected_kind: String) -> Dictionary:
|
||||||
):
|
):
|
||||||
return {"ok": false, "message": "progression container is malformed."}
|
return {"ok": false, "message": "progression container is malformed."}
|
||||||
var envelope: Dictionary = envelope_json.data
|
var envelope: Dictionary = envelope_json.data
|
||||||
|
var legacy_container: bool = envelope.get("magic") == LEGACY_MAGIC
|
||||||
if (
|
if (
|
||||||
envelope.get("magic") != MAGIC
|
envelope.get("magic") not in [MAGIC, LEGACY_MAGIC]
|
||||||
or int(envelope.get("format_version", -1)) != FORMAT_VERSION
|
or int(envelope.get("format_version", -1)) != FORMAT_VERSION
|
||||||
or str(envelope.get("kind", "")) != expected_kind
|
or str(envelope.get("kind", "")) != expected_kind
|
||||||
):
|
):
|
||||||
|
|
@ -144,9 +142,23 @@ static func _read_container(path: String, expected_kind: String) -> Dictionary:
|
||||||
"game_version": str(envelope.get("game_version", "")),
|
"game_version": str(envelope.get("game_version", "")),
|
||||||
"created_at_unix": int(envelope.get("created_at_unix", 0)),
|
"created_at_unix": int(envelope.get("created_at_unix", 0)),
|
||||||
"legacy_plaintext": false,
|
"legacy_plaintext": false,
|
||||||
|
"legacy_container": legacy_container,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func _read_encrypted_text(path: String) -> String:
|
||||||
|
var file: FileAccess = FileAccess.open_encrypted_with_pass(
|
||||||
|
path,
|
||||||
|
FileAccess.READ,
|
||||||
|
CONTAINER_PASSPHRASE,
|
||||||
|
)
|
||||||
|
if file == null:
|
||||||
|
return ""
|
||||||
|
var text: String = file.get_as_text()
|
||||||
|
file.close()
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
static func _read_plaintext_dictionary(path: String) -> Dictionary:
|
static func _read_plaintext_dictionary(path: String) -> Dictionary:
|
||||||
var bytes: PackedByteArray = PortableFileGuard.read_bytes(
|
var bytes: PackedByteArray = PortableFileGuard.read_bytes(
|
||||||
path,
|
path,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ set -euo pipefail
|
||||||
|
|
||||||
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||||
readonly OUTPUT_PATH="${PROJECT_ROOT}/builds/android/NETfishing-debug.apk"
|
readonly OUTPUT_PATH="${PROJECT_ROOT}/builds/android/straywild-debug.apk"
|
||||||
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
||||||
|
|
||||||
mkdir -p -- "$(dirname -- "${OUTPUT_PATH}")"
|
mkdir -p -- "$(dirname -- "${OUTPUT_PATH}")"
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ set -euo pipefail
|
||||||
|
|
||||||
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||||
readonly BUILD_ROOT="${PROJECT_ROOT}/builds/v0.18.0-alpha"
|
readonly BUILD_ROOT="${PROJECT_ROOT}/builds/v0.19.0-alpha"
|
||||||
readonly WINDOWS_DIR="${BUILD_ROOT}/windows-x86_64"
|
readonly WINDOWS_DIR="${BUILD_ROOT}/windows-x86_64"
|
||||||
readonly LINUX_DIR="${BUILD_ROOT}/linux-x86_64"
|
readonly LINUX_DIR="${BUILD_ROOT}/linux-x86_64"
|
||||||
readonly README_SOURCE="${PROJECT_ROOT}/docs/README-PLAYTEST.txt"
|
readonly README_SOURCE="${PROJECT_ROOT}/docs/README-PLAYTEST.txt"
|
||||||
readonly SOURCE_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)"
|
readonly SOURCE_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)"
|
||||||
readonly SOURCE_URL="https://forge.makearmy.io/woofmeow/netfishing"
|
readonly SOURCE_URL="https://forge.makearmy.io/woofmeow/straywild"
|
||||||
readonly WINDOWS_ZIP="${BUILD_ROOT}/NETfishing-v0.18.0-alpha-windows-x86_64.zip"
|
readonly WINDOWS_ZIP="${BUILD_ROOT}/straywild-v0.19.0-alpha-windows-x86_64.zip"
|
||||||
readonly LINUX_ZIP="${BUILD_ROOT}/NETfishing-v0.18.0-alpha-linux-x86_64.zip"
|
readonly LINUX_ZIP="${BUILD_ROOT}/straywild-v0.19.0-alpha-linux-x86_64.zip"
|
||||||
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
||||||
|
|
||||||
if [[ ! -f "${PROJECT_ROOT}/project.godot" ]]; then
|
if [[ ! -f "${PROJECT_ROOT}/project.godot" ]]; then
|
||||||
|
|
@ -31,26 +31,26 @@ mkdir -p -- "${WINDOWS_DIR}" "${LINUX_DIR}"
|
||||||
--headless \
|
--headless \
|
||||||
--path "${PROJECT_ROOT}" \
|
--path "${PROJECT_ROOT}" \
|
||||||
--export-release "Windows Desktop" \
|
--export-release "Windows Desktop" \
|
||||||
"${WINDOWS_DIR}/NETfishing.exe"
|
"${WINDOWS_DIR}/straywild.exe"
|
||||||
|
|
||||||
"${GODOT_BIN}" \
|
"${GODOT_BIN}" \
|
||||||
--headless \
|
--headless \
|
||||||
--path "${PROJECT_ROOT}" \
|
--path "${PROJECT_ROOT}" \
|
||||||
--export-release "Linux Desktop" \
|
--export-release "Linux Desktop" \
|
||||||
"${LINUX_DIR}/NETfishing.x86_64"
|
"${LINUX_DIR}/straywild.x86_64"
|
||||||
|
|
||||||
for required_file in \
|
for required_file in \
|
||||||
"${WINDOWS_DIR}/NETfishing.exe" \
|
"${WINDOWS_DIR}/straywild.exe" \
|
||||||
"${WINDOWS_DIR}/NETfishing.pck" \
|
"${WINDOWS_DIR}/straywild.pck" \
|
||||||
"${LINUX_DIR}/NETfishing.x86_64" \
|
"${LINUX_DIR}/straywild.x86_64" \
|
||||||
"${LINUX_DIR}/NETfishing.pck"; do
|
"${LINUX_DIR}/straywild.pck"; do
|
||||||
if [[ ! -s "${required_file}" ]]; then
|
if [[ ! -s "${required_file}" ]]; then
|
||||||
echo "error: expected export output is missing: ${required_file}" >&2
|
echo "error: expected export output is missing: ${required_file}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
chmod +x -- "${LINUX_DIR}/NETfishing.x86_64"
|
chmod +x -- "${LINUX_DIR}/straywild.x86_64"
|
||||||
cp -- "${README_SOURCE}" "${WINDOWS_DIR}/README-PLAYTEST.txt"
|
cp -- "${README_SOURCE}" "${WINDOWS_DIR}/README-PLAYTEST.txt"
|
||||||
cp -- "${README_SOURCE}" "${LINUX_DIR}/README-PLAYTEST.txt"
|
cp -- "${README_SOURCE}" "${LINUX_DIR}/README-PLAYTEST.txt"
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ stage_licenses() {
|
||||||
install -m 0644 "${PROJECT_ROOT}/LICENSE" \
|
install -m 0644 "${PROJECT_ROOT}/LICENSE" \
|
||||||
"${destination}/GPL-3.0-or-later.txt"
|
"${destination}/GPL-3.0-or-later.txt"
|
||||||
install -m 0644 "${PROJECT_ROOT}/ASSET-LICENSE.md" \
|
install -m 0644 "${PROJECT_ROOT}/ASSET-LICENSE.md" \
|
||||||
"${destination}/NETFISHING-ASSET-LICENSE.md"
|
"${destination}/straywild-ASSET-LICENSE.md"
|
||||||
install -m 0644 "${PROJECT_ROOT}/docs/ATTRIBUTION.md" \
|
install -m 0644 "${PROJECT_ROOT}/docs/ATTRIBUTION.md" \
|
||||||
"${destination}/ATTRIBUTION.md"
|
"${destination}/ATTRIBUTION.md"
|
||||||
install -m 0644 "${PROJECT_ROOT}/TRADEMARKS.md" \
|
install -m 0644 "${PROJECT_ROOT}/TRADEMARKS.md" \
|
||||||
|
|
@ -72,7 +72,7 @@ stage_licenses() {
|
||||||
cat >"${destination}/SOURCE-CODE.md" <<EOF
|
cat >"${destination}/SOURCE-CODE.md" <<EOF
|
||||||
# Corresponding source
|
# Corresponding source
|
||||||
|
|
||||||
NETfishing code is licensed under GPL-3.0-or-later.
|
straywild code is licensed under GPL-3.0-or-later.
|
||||||
|
|
||||||
Source repository: ${SOURCE_URL}
|
Source repository: ${SOURCE_URL}
|
||||||
Source revision at build time: ${SOURCE_COMMIT}
|
Source revision at build time: ${SOURCE_COMMIT}
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ fi
|
||||||
readonly RELEASE_TAG="v${PROJECT_VERSION}"
|
readonly RELEASE_TAG="v${PROJECT_VERSION}"
|
||||||
readonly RELEASE_ROOT="${PROJECT_ROOT}/builds/${RELEASE_TAG}"
|
readonly RELEASE_ROOT="${PROJECT_ROOT}/builds/${RELEASE_TAG}"
|
||||||
readonly ARM64_ROOT="${RELEASE_ROOT}/linux-arm64"
|
readonly ARM64_ROOT="${RELEASE_ROOT}/linux-arm64"
|
||||||
readonly ARM64_EXECUTABLE="${ARM64_ROOT}/NETfishing.arm64"
|
readonly ARM64_EXECUTABLE="${ARM64_ROOT}/straywild.arm64"
|
||||||
readonly ARM64_PCK="${ARM64_ROOT}/NETfishing.pck"
|
readonly ARM64_PCK="${ARM64_ROOT}/straywild.pck"
|
||||||
readonly STAGE_ROOT="${RELEASE_ROOT}/portmaster-stage"
|
readonly STAGE_ROOT="${RELEASE_ROOT}/portmaster-stage"
|
||||||
readonly GAME_ROOT="${STAGE_ROOT}/netfishing"
|
readonly GAME_ROOT="${STAGE_ROOT}/straywild"
|
||||||
readonly ARCHIVE="${RELEASE_ROOT}/netfishing.zip"
|
readonly ARCHIVE="${RELEASE_ROOT}/straywild.zip"
|
||||||
readonly OBSOLETE_VERSIONED_ARCHIVE="${RELEASE_ROOT}/NETfishing-${RELEASE_TAG}-portmaster-arm64.zip"
|
readonly OBSOLETE_VERSIONED_ARCHIVE="${RELEASE_ROOT}/straywild-${RELEASE_TAG}-portmaster-arm64.zip"
|
||||||
readonly OBSOLETE_LOWERCASE_ARCHIVE="${RELEASE_ROOT}/netfishing-${RELEASE_TAG}-portmaster-arm64.zip"
|
readonly OBSOLETE_LOWERCASE_ARCHIVE="${RELEASE_ROOT}/straywild-${RELEASE_TAG}-portmaster-arm64.zip"
|
||||||
|
|
||||||
readonly HEAD_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)"
|
readonly HEAD_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)"
|
||||||
readonly TAG_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse "${RELEASE_TAG}^{commit}")"
|
readonly TAG_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse "${RELEASE_TAG}^{commit}")"
|
||||||
|
|
@ -74,7 +74,7 @@ elif [[ "${HEAD_COMMIT}" != "${TAG_COMMIT}" ]]; then
|
||||||
echo "HEAD does not match ${RELEASE_TAG}. Refusing to package mutable source." >&2
|
echo "HEAD does not match ${RELEASE_TAG}. Refusing to package mutable source." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ "${NETFISHING_ALLOW_DIRTY_RELEASE:-0}" != "1" ]]; then
|
if [[ "${straywild_ALLOW_DIRTY_RELEASE:-0}" != "1" ]]; then
|
||||||
dirty_tree=0
|
dirty_tree=0
|
||||||
git -C "${PROJECT_ROOT}" diff --quiet || dirty_tree=1
|
git -C "${PROJECT_ROOT}" diff --quiet || dirty_tree=1
|
||||||
git -C "${PROJECT_ROOT}" diff --cached --quiet || dirty_tree=1
|
git -C "${PROJECT_ROOT}" diff --cached --quiet || dirty_tree=1
|
||||||
|
|
@ -97,7 +97,7 @@ done
|
||||||
mkdir -p -- "${ARM64_ROOT}" "${RELEASE_ROOT}"
|
mkdir -p -- "${ARM64_ROOT}" "${RELEASE_ROOT}"
|
||||||
if [[ ${PACKAGE_ONLY} -eq 0 ]]; then
|
if [[ ${PACKAGE_ONLY} -eq 0 ]]; then
|
||||||
readonly EXPORT_PROJECT_ROOT="$(
|
readonly EXPORT_PROJECT_ROOT="$(
|
||||||
mktemp -d -t netfishing-portmaster-export.XXXXXX
|
mktemp -d -t straywild-portmaster-export.XXXXXX
|
||||||
)"
|
)"
|
||||||
cleanup_export_project() {
|
cleanup_export_project() {
|
||||||
rm -rf -- "${EXPORT_PROJECT_ROOT}"
|
rm -rf -- "${EXPORT_PROJECT_ROOT}"
|
||||||
|
|
@ -108,9 +108,9 @@ if [[ ${PACKAGE_ONLY} -eq 0 ]]; then
|
||||||
--exclude '/.git/' \
|
--exclude '/.git/' \
|
||||||
--exclude '/.godot/' \
|
--exclude '/.godot/' \
|
||||||
--exclude '/art/source/' \
|
--exclude '/art/source/' \
|
||||||
--exclude '/art/exported/system_icons/netfishing.ico' \
|
--exclude '/art/exported/system_icons/straywild.ico' \
|
||||||
--exclude '/art/exported/system_icons/netfishing_1024.png' \
|
--exclude '/art/exported/system_icons/straywild_1024.png' \
|
||||||
--exclude '/art/exported/system_icons/netfishing_1024.png.import' \
|
--exclude '/art/exported/system_icons/straywild_1024.png.import' \
|
||||||
--exclude '/audio/ambience/' \
|
--exclude '/audio/ambience/' \
|
||||||
--exclude '/builds/' \
|
--exclude '/builds/' \
|
||||||
--exclude '/docs/design/' \
|
--exclude '/docs/design/' \
|
||||||
|
|
@ -141,14 +141,14 @@ rm -f -- \
|
||||||
"${OBSOLETE_LOWERCASE_ARCHIVE}"
|
"${OBSOLETE_LOWERCASE_ARCHIVE}"
|
||||||
mkdir -p -- "${GAME_ROOT}/licenses"
|
mkdir -p -- "${GAME_ROOT}/licenses"
|
||||||
|
|
||||||
install -m 0755 "${TEMPLATE_ROOT}/NETfishing.sh" "${STAGE_ROOT}/NETfishing.sh"
|
install -m 0755 "${TEMPLATE_ROOT}/straywild.sh" "${STAGE_ROOT}/straywild.sh"
|
||||||
install -m 0644 "${TEMPLATE_ROOT}/port.json" "${GAME_ROOT}/port.json"
|
install -m 0644 "${TEMPLATE_ROOT}/port.json" "${GAME_ROOT}/port.json"
|
||||||
install -m 0644 "${TEMPLATE_ROOT}/netfishing.gptk" \
|
install -m 0644 "${TEMPLATE_ROOT}/straywild.gptk" \
|
||||||
"${GAME_ROOT}/netfishing.gptk"
|
"${GAME_ROOT}/straywild.gptk"
|
||||||
install -m 0755 "${TEMPLATE_ROOT}/launch-netfishing.sh" \
|
install -m 0755 "${TEMPLATE_ROOT}/launch-straywild.sh" \
|
||||||
"${GAME_ROOT}/launch-netfishing.sh"
|
"${GAME_ROOT}/launch-straywild.sh"
|
||||||
install -m 0755 "${ARM64_EXECUTABLE}" "${GAME_ROOT}/NETfishing.aarch64"
|
install -m 0755 "${ARM64_EXECUTABLE}" "${GAME_ROOT}/straywild.aarch64"
|
||||||
install -m 0644 "${ARM64_PCK}" "${GAME_ROOT}/NETfishing.pck"
|
install -m 0644 "${ARM64_PCK}" "${GAME_ROOT}/straywild.pck"
|
||||||
install -m 0644 "${TEMPLATE_ROOT}/gameinfo.xml" "${GAME_ROOT}/gameinfo.xml"
|
install -m 0644 "${TEMPLATE_ROOT}/gameinfo.xml" "${GAME_ROOT}/gameinfo.xml"
|
||||||
install -m 0644 "${TEMPLATE_ROOT}/screenshot.png" "${GAME_ROOT}/screenshot.png"
|
install -m 0644 "${TEMPLATE_ROOT}/screenshot.png" "${GAME_ROOT}/screenshot.png"
|
||||||
install -m 0644 \
|
install -m 0644 \
|
||||||
|
|
@ -159,7 +159,7 @@ install -m 0644 \
|
||||||
"${GAME_ROOT}/licenses/GPL-3.0-or-later.txt"
|
"${GAME_ROOT}/licenses/GPL-3.0-or-later.txt"
|
||||||
install -m 0644 \
|
install -m 0644 \
|
||||||
"${PROJECT_ROOT}/ASSET-LICENSE.md" \
|
"${PROJECT_ROOT}/ASSET-LICENSE.md" \
|
||||||
"${GAME_ROOT}/licenses/NETFISHING-ASSET-LICENSE.md"
|
"${GAME_ROOT}/licenses/straywild-ASSET-LICENSE.md"
|
||||||
install -m 0644 \
|
install -m 0644 \
|
||||||
"${PROJECT_ROOT}/TRADEMARKS.md" \
|
"${PROJECT_ROOT}/TRADEMARKS.md" \
|
||||||
"${GAME_ROOT}/licenses/TRADEMARKS.md"
|
"${GAME_ROOT}/licenses/TRADEMARKS.md"
|
||||||
|
|
@ -171,7 +171,7 @@ install -m 0644 \
|
||||||
"${GAME_ROOT}/licenses/Seattle-Avenue-LICENSE.txt"
|
"${GAME_ROOT}/licenses/Seattle-Avenue-LICENSE.txt"
|
||||||
|
|
||||||
cat >"${GAME_ROOT}/BUILD-INFO.txt" <<EOF
|
cat >"${GAME_ROOT}/BUILD-INFO.txt" <<EOF
|
||||||
NETfishing PortMaster ARM64 build
|
straywild PortMaster ARM64 build
|
||||||
|
|
||||||
Project version: ${PROJECT_VERSION}
|
Project version: ${PROJECT_VERSION}
|
||||||
Game source commit: ${TAG_COMMIT}
|
Game source commit: ${TAG_COMMIT}
|
||||||
|
|
@ -191,105 +191,109 @@ EOF
|
||||||
cat >"${GAME_ROOT}/licenses/SOURCE-CODE.md" <<EOF
|
cat >"${GAME_ROOT}/licenses/SOURCE-CODE.md" <<EOF
|
||||||
# Corresponding source
|
# Corresponding source
|
||||||
|
|
||||||
NETfishing code is licensed under GPL-3.0-or-later.
|
straywild code is licensed under GPL-3.0-or-later.
|
||||||
|
|
||||||
Source repository: https://forge.makearmy.io/woofmeow/netfishing
|
Source repository: https://forge.makearmy.io/woofmeow/straywild
|
||||||
Exact source revision: ${TAG_COMMIT}
|
Exact source revision: ${TAG_COMMIT}
|
||||||
Release tag: ${RELEASE_TAG}
|
Release tag: ${RELEASE_TAG}
|
||||||
PortMaster packaging revision: ${HEAD_COMMIT}
|
PortMaster packaging revision: ${HEAD_COMMIT}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat >"${GAME_ROOT}/README.md" <<EOF
|
cat >"${GAME_ROOT}/README.md" <<EOF
|
||||||
# NETfishing for PortMaster
|
# straywild for PortMaster
|
||||||
|
|
||||||
This package contains NETfishing \`${RELEASE_TAG}\`, exported from Godot 4.7.1
|
This package contains straywild \`${RELEASE_TAG}\`, exported from Godot 4.7.1
|
||||||
for 64-bit ARM Linux and wrapped for PortMaster.
|
for 64-bit ARM Linux and wrapped for PortMaster.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Install the complete \`netfishing.zip\` archive with PortMaster or HarbourMaster.
|
Install the complete \`straywild.zip\` archive with PortMaster or HarbourMaster.
|
||||||
The package requires an ARM64 device, two analog sticks, GLIBC 2.28 or newer,
|
The package requires an ARM64 device, two analog sticks, GLIBC 2.28 or newer,
|
||||||
and the \`weston_pkg_0.2\` runtime.
|
and the \`weston_pkg_0.2\` runtime.
|
||||||
|
|
||||||
New installations store player data under \`ports/saves/netfishing/\` without
|
New installations store player data under \`ports/saves/straywild/\` without
|
||||||
opening a folder picker. Existing installations preserve their previously
|
opening a folder picker. Existing installations preserve their previously
|
||||||
selected data root. Device-local configuration remains under
|
selected data root. Device-local configuration remains under
|
||||||
\`netfishing/conf/\`.
|
\`straywild/conf/\`.
|
||||||
PortMaster launches use the light performance profile by default. Put the word
|
PortMaster launches use the light performance profile by default. Put the word
|
||||||
\`normal\` in \`netfishing/conf/performance_profile\` to opt a capable device
|
\`normal\` in \`straywild/conf/performance_profile\` to opt a capable device
|
||||||
into the normal rendering profile. PortMaster packages retain title and world
|
into the normal rendering profile. PortMaster packages retain title and world
|
||||||
music while omitting rain and shoreline ambience in both profiles. See
|
music while omitting rain and shoreline ambience in both profiles. See
|
||||||
\`netfishing/licenses/\` for bundled credits and license information.
|
\`straywild/licenses/\` for bundled credits and license information.
|
||||||
|
|
||||||
## Controls
|
## Controls
|
||||||
|
|
||||||
NETfishing reads the handheld controller directly. GPTOKEYB's device-specific
|
straywild reads the handheld controller directly. GPTOKEYB's device-specific
|
||||||
force-quit chord remains available; this is Start+Select on most devices.
|
force-quit chord remains available; this is Start+Select on most devices.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
(
|
(
|
||||||
cd "${STAGE_ROOT}"
|
cd "${STAGE_ROOT}"
|
||||||
zip -qry "${ARCHIVE}" NETfishing.sh netfishing
|
zip -qry "${ARCHIVE}" straywild.sh straywild
|
||||||
)
|
)
|
||||||
|
|
||||||
unzip -tq "${ARCHIVE}" >/dev/null
|
unzip -tq "${ARCHIVE}" >/dev/null
|
||||||
readonly TOP_LEVELS="$(
|
readonly TOP_LEVELS="$(
|
||||||
unzip -Z1 "${ARCHIVE}" | cut -d/ -f1 | sort -u
|
unzip -Z1 "${ARCHIVE}" | cut -d/ -f1 | sort -u
|
||||||
)"
|
)"
|
||||||
readonly EXPECTED_TOP_LEVELS="$(printf '%s\n' NETfishing.sh netfishing)"
|
readonly EXPECTED_TOP_LEVELS="$(printf '%s\n' straywild.sh straywild)"
|
||||||
if [[ "${TOP_LEVELS}" != "${EXPECTED_TOP_LEVELS}" ]]; then
|
if [[ "${TOP_LEVELS}" != "${EXPECTED_TOP_LEVELS}" ]]; then
|
||||||
echo "Unexpected PortMaster archive roots:" >&2
|
echo "Unexpected PortMaster archive roots:" >&2
|
||||||
printf '%s\n' "${TOP_LEVELS}" >&2
|
printf '%s\n' "${TOP_LEVELS}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
grep -q '"version": 4' "${GAME_ROOT}/port.json"
|
grep -q '"version": 4' "${GAME_ROOT}/port.json"
|
||||||
grep -q '"name": "netfishing.zip"' "${GAME_ROOT}/port.json"
|
grep -q '"name": "straywild.zip"' "${GAME_ROOT}/port.json"
|
||||||
grep -q '"rtr": true' "${GAME_ROOT}/port.json"
|
grep -q '"rtr": true' "${GAME_ROOT}/port.json"
|
||||||
if unzip -Z1 "${ARCHIVE}" | grep -qx 'port.json'; then
|
if unzip -Z1 "${ARCHIVE}" | grep -qx 'port.json'; then
|
||||||
echo "port.json must be inside netfishing/, not at the archive root." >&2
|
echo "port.json must be inside straywild/, not at the archive root." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if grep -Eq '^[[:space:]]*#[[:space:]]*PORTMASTER:' \
|
if grep -Eq '^[[:space:]]*#[[:space:]]*PORTMASTER:' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"; then
|
"${STAGE_ROOT}/straywild.sh"; then
|
||||||
echo "The distributable launcher contains an installed PortMaster signature." >&2
|
echo "The distributable launcher contains an installed PortMaster signature." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
grep -Fq 'PROFILE_PATH="$CONFDIR/performance_profile"' \
|
grep -Fq 'PROFILE_PATH="$CONFDIR/performance_profile"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'NETFISHING_PERFORMANCE_PROFILE=light' \
|
grep -Fq 'straywild_PERFORMANCE_PROFILE=light' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'CONTROLLER_MAPPING_FILE="$CONFDIR/cache/controller_mapping.txt"' \
|
grep -Fq 'CONTROLLER_MAPPING_FILE="$CONFDIR/cache/controller_mapping.txt"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'SAVEDIR="$PORTS_ROOT/saves/netfishing"' \
|
grep -Fq 'SAVEDIR="$PORTS_ROOT/saves/straywild"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq '"NETFISHING_DATA_DIR=$SAVEDIR"' \
|
grep -Fq 'LEGACY_SAVEDIR="$PORTS_ROOT/saves/netfishing"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq '"NETFISHING_CREATE_DATA_DIR=1"' \
|
grep -Fq 'cp -a "$LEGACY_CONFDIR/." "$CONFDIR/"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'printf '\''%s\n'\'' "$netfishing_controllerconfig" > "$CONTROLLER_MAPPING_FILE"' \
|
grep -Fq '"straywild_DATA_DIR=$SAVEDIR"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq '"$GAME_LAUNCHER"' "${STAGE_ROOT}/NETfishing.sh"
|
grep -Fq '"straywild_CREATE_DATA_DIR=1"' \
|
||||||
grep -Fq '"$CONTROLLER_MAPPING_FILE"' "${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
if grep -Fq 'SDL_GAMECONTROLLERCONFIG="$netfishing_controllerconfig"' \
|
grep -Fq 'printf '\''%s\n'\'' "$straywild_controllerconfig" > "$CONTROLLER_MAPPING_FILE"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"; then
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
|
grep -Fq '"$GAME_LAUNCHER"' "${STAGE_ROOT}/straywild.sh"
|
||||||
|
grep -Fq '"$CONTROLLER_MAPPING_FILE"' "${STAGE_ROOT}/straywild.sh"
|
||||||
|
if grep -Fq 'SDL_GAMECONTROLLERCONFIG="$straywild_controllerconfig"' \
|
||||||
|
"${STAGE_ROOT}/straywild.sh"; then
|
||||||
echo "Raw controller mappings must not be passed through westonwrap.sh." >&2
|
echo "Raw controller mappings must not be passed through westonwrap.sh." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
grep -Fq 'SDL_GAMECONTROLLERCONFIG="$(<"$CONTROLLER_MAPPING_FILE")"' \
|
grep -Fq 'SDL_GAMECONTROLLERCONFIG="$(<"$CONTROLLER_MAPPING_FILE")"' \
|
||||||
"${GAME_ROOT}/launch-netfishing.sh"
|
"${GAME_ROOT}/launch-straywild.sh"
|
||||||
grep -Fq 'export SDL_GAMECONTROLLERCONFIG' \
|
grep -Fq 'export SDL_GAMECONTROLLERCONFIG' \
|
||||||
"${GAME_ROOT}/launch-netfishing.sh"
|
"${GAME_ROOT}/launch-straywild.sh"
|
||||||
grep -Fq 'exec "$@"' "${GAME_ROOT}/launch-netfishing.sh"
|
grep -Fq 'exec "$@"' "${GAME_ROOT}/launch-straywild.sh"
|
||||||
grep -Fq 'GPTOKEYB_CONFIG="$GAMEDIR/netfishing.gptk"' \
|
grep -Fq 'GPTOKEYB_CONFIG="$GAMEDIR/straywild.gptk"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq '$GPTOKEYB "NETfishing.aarch64" -c "$GPTOKEYB_CONFIG" &' \
|
grep -Fq '$GPTOKEYB "straywild.aarch64" -c "$GPTOKEYB_CONFIG" &' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'pm_platform_helper "$GAME_EXECUTABLE"' \
|
grep -Fq 'pm_platform_helper "$GAME_EXECUTABLE"' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh"
|
"${STAGE_ROOT}/straywild.sh"
|
||||||
grep -Fq 'pm_finish' "${STAGE_ROOT}/NETfishing.sh"
|
grep -Fq 'pm_finish' "${STAGE_ROOT}/straywild.sh"
|
||||||
if [[ "$(grep -Ec '^[[:space:]]*\$GPTOKEYB[[:space:]]' \
|
if [[ "$(grep -Ec '^[[:space:]]*\$GPTOKEYB[[:space:]]' \
|
||||||
"${STAGE_ROOT}/NETfishing.sh")" -ne 1 ]]; then
|
"${STAGE_ROOT}/straywild.sh")" -ne 1 ]]; then
|
||||||
echo "NETfishing must start exactly one GPTOKEYB exit handler." >&2
|
echo "straywild must start exactly one GPTOKEYB exit handler." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
readonly GPTOKEYB_NOOP_KEYS=(
|
readonly GPTOKEYB_NOOP_KEYS=(
|
||||||
|
|
@ -303,13 +307,13 @@ readonly GPTOKEYB_NOOP_KEYS=(
|
||||||
for noop_key in "${GPTOKEYB_NOOP_KEYS[@]}"; do
|
for noop_key in "${GPTOKEYB_NOOP_KEYS[@]}"; do
|
||||||
if ! grep -Eq \
|
if ! grep -Eq \
|
||||||
"^[[:space:]]*${noop_key}[[:space:]]*=[[:space:]]*\\\\\"[[:space:]]*$" \
|
"^[[:space:]]*${noop_key}[[:space:]]*=[[:space:]]*\\\\\"[[:space:]]*$" \
|
||||||
"${GAME_ROOT}/netfishing.gptk"; then
|
"${GAME_ROOT}/straywild.gptk"; then
|
||||||
echo "GPTOKEYB no-op mapping is missing: ${noop_key}" >&2
|
echo "GPTOKEYB no-op mapping is missing: ${noop_key}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [[ "$(grep -Ec '^[[:space:]]*[a-z0-9_]+[[:space:]]*=' \
|
if [[ "$(grep -Ec '^[[:space:]]*[a-z0-9_]+[[:space:]]*=' \
|
||||||
"${GAME_ROOT}/netfishing.gptk")" -ne "${#GPTOKEYB_NOOP_KEYS[@]}" ]]; then
|
"${GAME_ROOT}/straywild.gptk")" -ne "${#GPTOKEYB_NOOP_KEYS[@]}" ]]; then
|
||||||
echo "GPTOKEYB no-op mapping contains an unexpected assignment." >&2
|
echo "GPTOKEYB no-op mapping contains an unexpected assignment." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@ if [[ ! "$SAMPLE_SET_DIRECTORY" =~ ^[a-z0-9_-]+$ ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
readonly DESTINATION_DIRECTORY="$PROJECT_ROOT/sound/dialogue/animalese/$SAMPLE_SET_DIRECTORY"
|
readonly DESTINATION_DIRECTORY="$PROJECT_ROOT/sound/dialogue/animalese/$SAMPLE_SET_DIRECTORY"
|
||||||
readonly WORK_DIRECTORY="$(mktemp -d -t netfishing-animalese-import.XXXXXX)"
|
readonly WORK_DIRECTORY="$(mktemp -d -t straywild-animalese-import.XXXXXX)"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
if [[ "$WORK_DIRECTORY" == /tmp/netfishing-animalese-import.* ]]; then
|
if [[ "$WORK_DIRECTORY" == /tmp/straywild-animalese-import.* ]]; then
|
||||||
find "$WORK_DIRECTORY" -depth -delete
|
find "$WORK_DIRECTORY" -depth -delete
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ fi
|
||||||
|
|
||||||
readonly ROOT_PATH="$1"
|
readonly ROOT_PATH="$1"
|
||||||
|
|
||||||
readonly WORK_ROOT="$(mktemp -d -t netfishing-godot-data.XXXXXX)"
|
readonly WORK_ROOT="$(mktemp -d -t straywild-godot-data.XXXXXX)"
|
||||||
trap 'rm -rf -- "${WORK_ROOT}"' EXIT
|
trap 'rm -rf -- "${WORK_ROOT}"' EXIT
|
||||||
|
|
||||||
cd "${PROJECT_ROOT}"
|
cd "${PROJECT_ROOT}"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<gameList>
|
<gameList>
|
||||||
<game>
|
<game>
|
||||||
<path>./NETfishing.sh</path>
|
<path>./straywild.sh</path>
|
||||||
<name>NETfishing</name>
|
<name>straywild</name>
|
||||||
<desc>A relaxed multiplayer fishing game about exploring a small island, catching and collecting fish, customizing your character, and spending time by the water.</desc>
|
<desc>A relaxed multiplayer fishing game about exploring a small island, catching and collecting fish, customizing your character, and spending time by the water.</desc>
|
||||||
<releasedate>20260804T000000</releasedate>
|
<releasedate>20260804T000000</releasedate>
|
||||||
<developer>NETfishing project</developer>
|
<developer>straywild project</developer>
|
||||||
<publisher>Independent</publisher>
|
<publisher>Independent</publisher>
|
||||||
<genre>adventure, simulation</genre>
|
<genre>adventure, simulation</genre>
|
||||||
<image>./netfishing/screenshot.png</image>
|
<image>./straywild/screenshot.png</image>
|
||||||
</game>
|
</game>
|
||||||
</gameList>
|
</gameList>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"name": "netfishing.zip",
|
"name": "straywild.zip",
|
||||||
"items": [
|
"items": [
|
||||||
"NETfishing.sh",
|
"straywild.sh",
|
||||||
"netfishing/"
|
"straywild/"
|
||||||
],
|
],
|
||||||
"items_opt": null,
|
"items_opt": null,
|
||||||
"attr": {
|
"attr": {
|
||||||
"title": "NETfishing",
|
"title": "straywild",
|
||||||
"porter": [
|
"porter": [
|
||||||
"Voyager"
|
"Voyager"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# NETfishing reads the controller directly. GPTOKEYB is retained only for its
|
# straywild reads the controller directly. GPTOKEYB is retained only for its
|
||||||
# device-specific force-quit chord, so every keyboard and mouse binding is
|
# device-specific force-quit chord, so every keyboard and mouse binding is
|
||||||
# disabled to prevent duplicate input.
|
# disabled to prevent duplicate input.
|
||||||
|
|
||||||
|
|
@ -16,35 +16,56 @@ source "$controlfolder/control.txt"
|
||||||
[ -f "${controlfolder}/mod_${CFW_NAME}.txt" ] && source "${controlfolder}/mod_${CFW_NAME}.txt"
|
[ -f "${controlfolder}/mod_${CFW_NAME}.txt" ] && source "${controlfolder}/mod_${CFW_NAME}.txt"
|
||||||
get_controls
|
get_controls
|
||||||
|
|
||||||
GAMEDIR="/${directory}/ports/netfishing"
|
GAMEDIR="/${directory}/ports/straywild"
|
||||||
|
|
||||||
CONFDIR="$GAMEDIR/conf"
|
CONFDIR="$GAMEDIR/conf"
|
||||||
PORTS_ROOT="${GAMEDIR%/netfishing}"
|
PORTS_ROOT="${GAMEDIR%/straywild}"
|
||||||
SAVEDIR="$PORTS_ROOT/saves/netfishing"
|
SAVEDIR="$PORTS_ROOT/saves/straywild"
|
||||||
DATA_BOOTSTRAP_DIR="$CONFDIR/data/godot/app_userdata/NETFISHING"
|
LEGACY_GAMEDIR="$PORTS_ROOT/netfishing"
|
||||||
GAME_EXECUTABLE="$GAMEDIR/NETfishing.aarch64"
|
LEGACY_CONFDIR="$LEGACY_GAMEDIR/conf"
|
||||||
GAME_LAUNCHER="$GAMEDIR/launch-netfishing.sh"
|
LEGACY_SAVEDIR="$PORTS_ROOT/saves/netfishing"
|
||||||
GPTOKEYB_CONFIG="$GAMEDIR/netfishing.gptk"
|
DATA_BOOTSTRAP_DIR="$CONFDIR/data/godot/app_userdata/straywild"
|
||||||
|
LEGACY_DATA_BOOTSTRAP_DIR="$CONFDIR/data/godot/app_userdata/NETFISHING"
|
||||||
|
GAME_EXECUTABLE="$GAMEDIR/straywild.aarch64"
|
||||||
|
GAME_LAUNCHER="$GAMEDIR/launch-straywild.sh"
|
||||||
|
GPTOKEYB_CONFIG="$GAMEDIR/straywild.gptk"
|
||||||
CONTROLLER_MAPPING_FILE="$CONFDIR/cache/controller_mapping.txt"
|
CONTROLLER_MAPPING_FILE="$CONFDIR/cache/controller_mapping.txt"
|
||||||
WESTON_DIR="/tmp/netfishing-weston"
|
WESTON_DIR="/tmp/straywild-weston"
|
||||||
WESTON_RUNTIME="weston_pkg_0.2"
|
WESTON_RUNTIME="weston_pkg_0.2"
|
||||||
HARBOURMASTER="$controlfolder/harbourmaster"
|
HARBOURMASTER="$controlfolder/harbourmaster"
|
||||||
|
|
||||||
mkdir -p "$CONFDIR/data" "$CONFDIR/config" "$CONFDIR/cache" "$WESTON_DIR"
|
mkdir -p "$CONFDIR/data" "$CONFDIR/config" "$CONFDIR/cache" "$WESTON_DIR"
|
||||||
chmod +x "$GAME_EXECUTABLE"
|
chmod +x "$GAME_EXECUTABLE"
|
||||||
|
|
||||||
# NETfishing uses a predictable save directory beside the port instead of
|
# A renamed PortMaster entry installs beside the former NETfishing port. Copy
|
||||||
|
# its device-local configuration once and continue using its established save
|
||||||
|
# root when present. New installations use straywild paths exclusively.
|
||||||
|
if [ -d "$LEGACY_CONFDIR" ] && [ ! -f "$CONFDIR/.netfishing-imported" ]; then
|
||||||
|
cp -a "$LEGACY_CONFDIR/." "$CONFDIR/"
|
||||||
|
touch "$CONFDIR/.netfishing-imported"
|
||||||
|
fi
|
||||||
|
if [ ! -f "$SAVEDIR/straywild_data.json" ] \
|
||||||
|
&& [ ! -f "$SAVEDIR/netfishing_data.json" ] \
|
||||||
|
&& { [ -f "$LEGACY_SAVEDIR/straywild_data.json" ] \
|
||||||
|
|| [ -f "$LEGACY_SAVEDIR/netfishing_data.json" ]; }; then
|
||||||
|
SAVEDIR="$LEGACY_SAVEDIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# straywild uses a predictable save directory beside the port instead of
|
||||||
# presenting a folder picker on a small screen. Preserve an established
|
# presenting a folder picker on a small screen. Preserve an established
|
||||||
# data-root choice when upgrading an existing installation.
|
# data-root choice when upgrading an existing installation.
|
||||||
NETFISHING_DATA_ENVIRONMENT=()
|
straywild_DATA_ENVIRONMENT=()
|
||||||
if [ -f "$SAVEDIR/netfishing_data.json" ] || {
|
if [ -f "$SAVEDIR/straywild_data.json" ] \
|
||||||
|
|| [ -f "$SAVEDIR/netfishing_data.json" ] || {
|
||||||
[ ! -f "$DATA_BOOTSTRAP_DIR/data_root_bootstrap.json" ] &&
|
[ ! -f "$DATA_BOOTSTRAP_DIR/data_root_bootstrap.json" ] &&
|
||||||
[ ! -f "$DATA_BOOTSTRAP_DIR/data_root_bootstrap.json.backup" ]
|
[ ! -f "$DATA_BOOTSTRAP_DIR/data_root_bootstrap.json.backup" ] &&
|
||||||
|
[ ! -f "$LEGACY_DATA_BOOTSTRAP_DIR/data_root_bootstrap.json" ] &&
|
||||||
|
[ ! -f "$LEGACY_DATA_BOOTSTRAP_DIR/data_root_bootstrap.json.backup" ]
|
||||||
}; then
|
}; then
|
||||||
mkdir -p "$SAVEDIR"
|
mkdir -p "$SAVEDIR"
|
||||||
NETFISHING_DATA_ENVIRONMENT+=(
|
straywild_DATA_ENVIRONMENT+=(
|
||||||
"NETFISHING_DATA_DIR=$SAVEDIR"
|
"straywild_DATA_DIR=$SAVEDIR"
|
||||||
"NETFISHING_CREATE_DATA_DIR=1"
|
"straywild_CREATE_DATA_DIR=1"
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -52,7 +73,7 @@ fi
|
||||||
|
|
||||||
if [ ! -f "$controlfolder/libs/${WESTON_RUNTIME}.squashfs" ]; then
|
if [ ! -f "$controlfolder/libs/${WESTON_RUNTIME}.squashfs" ]; then
|
||||||
if [ ! -x "$HARBOURMASTER" ]; then
|
if [ ! -x "$HARBOURMASTER" ]; then
|
||||||
pm_message "NETfishing requires the latest PortMaster and WestonPack runtime."
|
pm_message "straywild requires the latest PortMaster and WestonPack runtime."
|
||||||
sleep 5
|
sleep 5
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -78,17 +99,17 @@ cd "$GAMEDIR" || exit 1
|
||||||
GODOT_MUOS_MAPPING="19004ca6010000000100000000010000,muOS-Keys,a:b0,b:b1,x:b3,y:b2,leftshoulder:b4,rightshoulder:b5,lefttrigger:b10,righttrigger:b11,guide:b8,start:b7,back:b6,dpup:h0.1,dpleft:h0.8,dpright:h0.2,dpdown:h0.4,leftx:a0,lefty:a1,leftstick:b9,rightx:a2,righty:a3,rightstick:b12,platform:Linux,"
|
GODOT_MUOS_MAPPING="19004ca6010000000100000000010000,muOS-Keys,a:b0,b:b1,x:b3,y:b2,leftshoulder:b4,rightshoulder:b5,lefttrigger:b10,righttrigger:b11,guide:b8,start:b7,back:b6,dpup:h0.1,dpleft:h0.8,dpright:h0.2,dpdown:h0.4,leftx:a0,lefty:a1,leftstick:b9,rightx:a2,righty:a3,rightstick:b12,platform:Linux,"
|
||||||
MUOS_SDL2_GUID="19000000010000000100000000010000"
|
MUOS_SDL2_GUID="19000000010000000100000000010000"
|
||||||
if [[ "$sdl_controllerconfig" == "${MUOS_SDL2_GUID},"* ]]; then
|
if [[ "$sdl_controllerconfig" == "${MUOS_SDL2_GUID},"* ]]; then
|
||||||
netfishing_controllerconfig="$GODOT_MUOS_MAPPING"
|
straywild_controllerconfig="$GODOT_MUOS_MAPPING"
|
||||||
elif [ -n "$sdl_controllerconfig" ]; then
|
elif [ -n "$sdl_controllerconfig" ]; then
|
||||||
netfishing_controllerconfig="$sdl_controllerconfig"
|
straywild_controllerconfig="$sdl_controllerconfig"
|
||||||
else
|
else
|
||||||
netfishing_controllerconfig="$GODOT_MUOS_MAPPING"
|
straywild_controllerconfig="$GODOT_MUOS_MAPPING"
|
||||||
fi
|
fi
|
||||||
printf '%s\n' "$netfishing_controllerconfig" > "$CONTROLLER_MAPPING_FILE"
|
printf '%s\n' "$straywild_controllerconfig" > "$CONTROLLER_MAPPING_FILE"
|
||||||
|
|
||||||
NETFISHING_GODOT_OPTIONS=()
|
straywild_GODOT_OPTIONS=()
|
||||||
NETFISHING_GAME_ENVIRONMENT=()
|
straywild_GAME_ENVIRONMENT=()
|
||||||
PERFORMANCE_PROFILE="${NETFISHING_PERFORMANCE_PROFILE:-}"
|
PERFORMANCE_PROFILE="${straywild_PERFORMANCE_PROFILE:-}"
|
||||||
PROFILE_PATH="$CONFDIR/performance_profile"
|
PROFILE_PATH="$CONFDIR/performance_profile"
|
||||||
if [[ -z "$PERFORMANCE_PROFILE" && -r "$PROFILE_PATH" ]]; then
|
if [[ -z "$PERFORMANCE_PROFILE" && -r "$PROFILE_PATH" ]]; then
|
||||||
IFS= read -r PERFORMANCE_PROFILE < "$PROFILE_PATH" || true
|
IFS= read -r PERFORMANCE_PROFILE < "$PROFILE_PATH" || true
|
||||||
|
|
@ -96,16 +117,16 @@ if [[ -z "$PERFORMANCE_PROFILE" && -r "$PROFILE_PATH" ]]; then
|
||||||
fi
|
fi
|
||||||
case "$PERFORMANCE_PROFILE" in
|
case "$PERFORMANCE_PROFILE" in
|
||||||
normal)
|
normal)
|
||||||
NETFISHING_GAME_ENVIRONMENT+=(
|
straywild_GAME_ENVIRONMENT+=(
|
||||||
"NETFISHING_PERFORMANCE_PROFILE=normal"
|
"straywild_PERFORMANCE_PROFILE=normal"
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
light|"")
|
light|"")
|
||||||
NETFISHING_GAME_ENVIRONMENT+=(
|
straywild_GAME_ENVIRONMENT+=(
|
||||||
"NETFISHING_PERFORMANCE_PROFILE=light"
|
"straywild_PERFORMANCE_PROFILE=light"
|
||||||
"NETFISHING_LOW_END=1"
|
"straywild_LOW_END=1"
|
||||||
)
|
)
|
||||||
NETFISHING_GODOT_OPTIONS+=(
|
straywild_GODOT_OPTIONS+=(
|
||||||
--single-window
|
--single-window
|
||||||
--disable-vsync
|
--disable-vsync
|
||||||
--max-fps 30
|
--max-fps 30
|
||||||
|
|
@ -114,11 +135,11 @@ case "$PERFORMANCE_PROFILE" in
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown performance profile '$PERFORMANCE_PROFILE'; using light." >&2
|
echo "Unknown performance profile '$PERFORMANCE_PROFILE'; using light." >&2
|
||||||
NETFISHING_GAME_ENVIRONMENT+=(
|
straywild_GAME_ENVIRONMENT+=(
|
||||||
"NETFISHING_PERFORMANCE_PROFILE=light"
|
"straywild_PERFORMANCE_PROFILE=light"
|
||||||
"NETFISHING_LOW_END=1"
|
"straywild_LOW_END=1"
|
||||||
)
|
)
|
||||||
NETFISHING_GODOT_OPTIONS+=(
|
straywild_GODOT_OPTIONS+=(
|
||||||
--single-window
|
--single-window
|
||||||
--disable-vsync
|
--disable-vsync
|
||||||
--max-fps 30
|
--max-fps 30
|
||||||
|
|
@ -127,10 +148,10 @@ case "$PERFORMANCE_PROFILE" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# NETfishing reads gameplay input natively. The explicit no-op map prevents
|
# straywild reads gameplay input natively. The explicit no-op map prevents
|
||||||
# GPTOKEYB from injecting duplicate keyboard or mouse input while retaining
|
# GPTOKEYB from injecting duplicate keyboard or mouse input while retaining
|
||||||
# its device-specific force-quit chord, including on ROCKNIX.
|
# its device-specific force-quit chord, including on ROCKNIX.
|
||||||
$GPTOKEYB "NETfishing.aarch64" -c "$GPTOKEYB_CONFIG" &
|
$GPTOKEYB "straywild.aarch64" -c "$GPTOKEYB_CONFIG" &
|
||||||
pm_platform_helper "$GAME_EXECUTABLE"
|
pm_platform_helper "$GAME_EXECUTABLE"
|
||||||
|
|
||||||
$ESUDO env CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
|
$ESUDO env CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
|
||||||
|
|
@ -139,12 +160,12 @@ $ESUDO env CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
|
||||||
XDG_CONFIG_HOME="$CONFDIR/config" \
|
XDG_CONFIG_HOME="$CONFDIR/config" \
|
||||||
XDG_CACHE_HOME="$CONFDIR/cache" \
|
XDG_CACHE_HOME="$CONFDIR/cache" \
|
||||||
GODOT_SILENCE_ROOT_WARNING=1 \
|
GODOT_SILENCE_ROOT_WARNING=1 \
|
||||||
"${NETFISHING_DATA_ENVIRONMENT[@]}" \
|
"${straywild_DATA_ENVIRONMENT[@]}" \
|
||||||
"${NETFISHING_GAME_ENVIRONMENT[@]}" \
|
"${straywild_GAME_ENVIRONMENT[@]}" \
|
||||||
"$GAME_LAUNCHER" \
|
"$GAME_LAUNCHER" \
|
||||||
"$CONTROLLER_MAPPING_FILE" \
|
"$CONTROLLER_MAPPING_FILE" \
|
||||||
"$GAME_EXECUTABLE" \
|
"$GAME_EXECUTABLE" \
|
||||||
"${NETFISHING_GODOT_OPTIONS[@]}" \
|
"${straywild_GODOT_OPTIONS[@]}" \
|
||||||
--resolution "${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
|
--resolution "${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
|
||||||
--fullscreen \
|
--fullscreen \
|
||||||
--rendering-driver opengl3_es \
|
--rendering-driver opengl3_es \
|
||||||
|
|
@ -6,9 +6,9 @@ readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||||
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
readonly GODOT_BIN="${GODOT_BIN:-godot}"
|
||||||
readonly TEST_TIMEOUT_SECONDS="${TEST_TIMEOUT_SECONDS:-120}"
|
readonly TEST_TIMEOUT_SECONDS="${TEST_TIMEOUT_SECONDS:-120}"
|
||||||
readonly RUN_ROOT="$(mktemp -d -t netfishing-validations.XXXXXX)"
|
readonly RUN_ROOT="$(mktemp -d -t straywild-validations.XXXXXX)"
|
||||||
|
|
||||||
export NETFISHING_ISOLATED_VALIDATION_STORAGE=1
|
export straywild_ISOLATED_VALIDATION_STORAGE=1
|
||||||
|
|
||||||
readonly -a QUICK_TESTS=(
|
readonly -a QUICK_TESTS=(
|
||||||
"scripts/validate_animalese_samples.gd"
|
"scripts/validate_animalese_samples.gd"
|
||||||
|
|
|
||||||
|
|
@ -336,8 +336,8 @@ check_editor_settings() {
|
||||||
run_export_hint() {
|
run_export_hint() {
|
||||||
echo
|
echo
|
||||||
echo "Example export commands:"
|
echo "Example export commands:"
|
||||||
echo " ${GODOT} --headless --path \"$PROJECT_ROOT\" --export-release \"Android\" builds/${PROJECT_VERSION}/android/NETfishing.apk"
|
echo " ${GODOT} --headless --path \"$PROJECT_ROOT\" --export-release \"Android\" builds/${PROJECT_VERSION}/android/straywild.apk"
|
||||||
echo " ${GODOT} --headless --path \"$PROJECT_ROOT\" --export-debug \"Android\" builds/android/NETfishing-debug.apk"
|
echo " ${GODOT} --headless --path \"$PROJECT_ROOT\" --export-debug \"Android\" builds/android/straywild-debug.apk"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_status INFO "Starting Android dependency preflight..."
|
print_status INFO "Starting Android dependency preflight..."
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,36 @@
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
const PROJECT_PATH := "/tmp/netfishing"
|
const PROJECT_PATH := "/tmp/straywild"
|
||||||
const INSTALL_PATH := "/opt/NETfishing"
|
const INSTALL_PATH := "/opt/straywild"
|
||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
var root_to_create: String = OS.get_environment("NETFISHING_TEST_CREATE_ROOT")
|
var root_to_create: String = OS.get_environment("straywild_TEST_CREATE_ROOT")
|
||||||
if not root_to_create.is_empty():
|
if not root_to_create.is_empty():
|
||||||
_create_validation_root(root_to_create)
|
_create_validation_root(root_to_create)
|
||||||
return
|
return
|
||||||
var failures: PackedStringArray = []
|
var failures: PackedStringArray = []
|
||||||
_expect(
|
_expect(
|
||||||
"external temporary directory",
|
"external temporary directory",
|
||||||
"/tmp/NETfishing-test-data",
|
"/tmp/straywild-test-data",
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
failures,
|
failures,
|
||||||
)
|
)
|
||||||
_expect(
|
_expect(
|
||||||
"external trailing slash",
|
"external trailing slash",
|
||||||
"/tmp/NETfishing-test-data/",
|
"/tmp/straywild-test-data/",
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
failures,
|
failures,
|
||||||
)
|
)
|
||||||
_expect(
|
_expect(
|
||||||
"similar project-name sibling",
|
"similar project-name sibling",
|
||||||
"/tmp/netfishing-data",
|
"/tmp/straywild-data",
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
failures,
|
failures,
|
||||||
)
|
)
|
||||||
_expect(
|
_expect(
|
||||||
"documents directory",
|
"documents directory",
|
||||||
"/home/player/Documents/NETfishing",
|
"/home/player/Documents/straywild",
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
failures,
|
failures,
|
||||||
)
|
)
|
||||||
|
|
@ -55,7 +55,7 @@ func _initialize() -> void:
|
||||||
)
|
)
|
||||||
_expect_with_references(
|
_expect_with_references(
|
||||||
"empty project reference",
|
"empty project reference",
|
||||||
"/tmp/NETfishing-test-data",
|
"/tmp/straywild-test-data",
|
||||||
"",
|
"",
|
||||||
INSTALL_PATH,
|
INSTALL_PATH,
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
|
|
@ -63,7 +63,7 @@ func _initialize() -> void:
|
||||||
)
|
)
|
||||||
_expect_with_references(
|
_expect_with_references(
|
||||||
"root project reference",
|
"root project reference",
|
||||||
"/tmp/NETfishing-test-data",
|
"/tmp/straywild-test-data",
|
||||||
"/",
|
"/",
|
||||||
INSTALL_PATH,
|
INSTALL_PATH,
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
|
|
@ -71,9 +71,9 @@ func _initialize() -> void:
|
||||||
)
|
)
|
||||||
_expect_with_references(
|
_expect_with_references(
|
||||||
"Windows component and case normalization",
|
"Windows component and case normalization",
|
||||||
"C:\\Games\\NETfishing Data",
|
"C:\\Games\\straywild Data",
|
||||||
"C:\\Games\\NETfishing",
|
"C:\\Games\\straywild",
|
||||||
"C:\\Program Files\\NETfishing",
|
"C:\\Program Files\\straywild",
|
||||||
PlayerDataRoot.PATH_ALLOWED,
|
PlayerDataRoot.PATH_ALLOWED,
|
||||||
failures,
|
failures,
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
class_name DedicatedServerConfig
|
class_name DedicatedServerConfig
|
||||||
extends RefCounted
|
extends RefCounted
|
||||||
|
|
||||||
const DEFAULT_NAME: String = "NETfishing Dedicated Server"
|
const DEFAULT_NAME: String = "straywild Dedicated Server"
|
||||||
const DEFAULT_BIND_ADDRESS: String = "*"
|
const DEFAULT_BIND_ADDRESS: String = "*"
|
||||||
const DEFAULT_PORT: int = 7777
|
const DEFAULT_PORT: int = 7777
|
||||||
const DEFAULT_MAX_PLAYERS: int = 8
|
const DEFAULT_MAX_PLAYERS: int = 8
|
||||||
|
|
@ -31,8 +31,10 @@ static func from_runtime() -> DedicatedServerConfig:
|
||||||
result.discovery_url = str(ProjectSettings.get_setting(
|
result.discovery_url = str(ProjectSettings.get_setting(
|
||||||
"network/discovery/base_url", ""
|
"network/discovery/base_url", ""
|
||||||
)).strip_edges()
|
)).strip_edges()
|
||||||
var config_path: String = OS.get_environment(
|
var config_path: String = _environment_string(
|
||||||
"NETFISHING_SERVER_CONFIG"
|
"straywild_SERVER_CONFIG",
|
||||||
|
"NETFISHING_SERVER_CONFIG",
|
||||||
|
"",
|
||||||
).strip_edges()
|
).strip_edges()
|
||||||
for argument: String in OS.get_cmdline_user_args():
|
for argument: String in OS.get_cmdline_user_args():
|
||||||
if argument.begins_with("--config="):
|
if argument.begins_with("--config="):
|
||||||
|
|
@ -87,36 +89,44 @@ func _load_file(path: String) -> bool:
|
||||||
|
|
||||||
func _apply_environment() -> void:
|
func _apply_environment() -> void:
|
||||||
server_name = _environment_string(
|
server_name = _environment_string(
|
||||||
"NETFISHING_SERVER_NAME", server_name
|
"straywild_SERVER_NAME", "NETFISHING_SERVER_NAME", server_name
|
||||||
)
|
)
|
||||||
bind_address = _environment_string(
|
bind_address = _environment_string(
|
||||||
"NETFISHING_SERVER_BIND", bind_address
|
"straywild_SERVER_BIND", "NETFISHING_SERVER_BIND", bind_address
|
||||||
|
)
|
||||||
|
port = _environment_int(
|
||||||
|
"straywild_SERVER_PORT", "NETFISHING_SERVER_PORT", port
|
||||||
)
|
)
|
||||||
port = _environment_int("NETFISHING_SERVER_PORT", port)
|
|
||||||
max_players = _environment_int(
|
max_players = _environment_int(
|
||||||
"NETFISHING_SERVER_MAX_PLAYERS", max_players
|
"straywild_SERVER_MAX_PLAYERS",
|
||||||
|
"NETFISHING_SERVER_MAX_PLAYERS",
|
||||||
|
max_players,
|
||||||
)
|
)
|
||||||
world_seed = _environment_int(
|
world_seed = _environment_int(
|
||||||
"NETFISHING_WORLD_SEED", world_seed
|
"straywild_WORLD_SEED", "NETFISHING_WORLD_SEED", world_seed
|
||||||
)
|
)
|
||||||
public_listing = _environment_bool(
|
public_listing = _environment_bool(
|
||||||
"NETFISHING_SERVER_PUBLIC", public_listing
|
"straywild_SERVER_PUBLIC", "NETFISHING_SERVER_PUBLIC", public_listing
|
||||||
)
|
)
|
||||||
discovery_url = _environment_string(
|
discovery_url = _environment_string(
|
||||||
"NETFISHING_DISCOVERY_URL", discovery_url
|
"straywild_DISCOVERY_URL", "NETFISHING_DISCOVERY_URL", discovery_url
|
||||||
)
|
)
|
||||||
data_directory = _environment_string(
|
data_directory = _environment_string(
|
||||||
"NETFISHING_DATA_DIR", data_directory
|
"straywild_DATA_DIR", "NETFISHING_DATA_DIR", data_directory
|
||||||
)
|
)
|
||||||
chat_logging = _environment_bool(
|
chat_logging = _environment_bool(
|
||||||
"NETFISHING_CHAT_LOGGING", chat_logging
|
"straywild_CHAT_LOGGING", "NETFISHING_CHAT_LOGGING", chat_logging
|
||||||
)
|
)
|
||||||
chat_log_path = _environment_string(
|
chat_log_path = _environment_string(
|
||||||
"NETFISHING_CHAT_LOG_PATH", chat_log_path
|
"straywild_CHAT_LOG_PATH", "NETFISHING_CHAT_LOG_PATH", chat_log_path
|
||||||
)
|
)
|
||||||
if OS.has_environment("NETFISHING_SERVER_OPERATORS"):
|
var operators_variable: String = _available_environment_variable(
|
||||||
|
"straywild_SERVER_OPERATORS",
|
||||||
|
"NETFISHING_SERVER_OPERATORS",
|
||||||
|
)
|
||||||
|
if not operators_variable.is_empty():
|
||||||
operator_fingerprints = _parse_fingerprint_list(
|
operator_fingerprints = _parse_fingerprint_list(
|
||||||
OS.get_environment("NETFISHING_SERVER_OPERATORS")
|
OS.get_environment(operators_variable)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -211,21 +221,45 @@ static func _safe_text(value: String) -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
static func _environment_string(name: String, fallback: String) -> String:
|
static func _available_environment_variable(
|
||||||
return OS.get_environment(name) if OS.has_environment(name) else fallback
|
name: String,
|
||||||
|
legacy_name: String,
|
||||||
|
) -> String:
|
||||||
|
if OS.has_environment(name):
|
||||||
|
return name
|
||||||
|
return legacy_name if OS.has_environment(legacy_name) else ""
|
||||||
|
|
||||||
|
|
||||||
static func _environment_int(name: String, fallback: int) -> int:
|
static func _environment_string(
|
||||||
|
name: String,
|
||||||
|
legacy_name: String,
|
||||||
|
fallback: String,
|
||||||
|
) -> String:
|
||||||
|
var variable: String = _available_environment_variable(name, legacy_name)
|
||||||
|
return OS.get_environment(variable) if not variable.is_empty() else fallback
|
||||||
|
|
||||||
|
|
||||||
|
static func _environment_int(
|
||||||
|
name: String,
|
||||||
|
legacy_name: String,
|
||||||
|
fallback: int,
|
||||||
|
) -> int:
|
||||||
|
var variable: String = _available_environment_variable(name, legacy_name)
|
||||||
return (
|
return (
|
||||||
_parse_int(OS.get_environment(name), fallback)
|
_parse_int(OS.get_environment(variable), fallback)
|
||||||
if OS.has_environment(name) else fallback
|
if not variable.is_empty() else fallback
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
static func _environment_bool(name: String, fallback: bool) -> bool:
|
static func _environment_bool(
|
||||||
if not OS.has_environment(name):
|
name: String,
|
||||||
|
legacy_name: String,
|
||||||
|
fallback: bool,
|
||||||
|
) -> bool:
|
||||||
|
var variable: String = _available_environment_variable(name, legacy_name)
|
||||||
|
if variable.is_empty():
|
||||||
return fallback
|
return fallback
|
||||||
var value: String = OS.get_environment(name).strip_edges().to_lower()
|
var value: String = OS.get_environment(variable).strip_edges().to_lower()
|
||||||
return value in ["1", "true", "yes", "on"]
|
return value in ["1", "true", "yes", "on"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const TEMP_PATH: String = "user://player_settings.json.tmp"
|
||||||
const BACKUP_PATH: String = "user://player_settings.json.backup"
|
const BACKUP_PATH: String = "user://player_settings.json.backup"
|
||||||
const SILENT_VOLUME_DB: float = -80.0
|
const SILENT_VOLUME_DB: float = -80.0
|
||||||
const HEADLESS_WRITE_ENVIRONMENT: String = (
|
const HEADLESS_WRITE_ENVIRONMENT: String = (
|
||||||
"NETFISHING_ISOLATED_VALIDATION_STORAGE"
|
"straywild_ISOLATED_VALIDATION_STORAGE"
|
||||||
)
|
)
|
||||||
|
|
||||||
signal settings_changed(settings: PlayerSettings)
|
signal settings_changed(settings: PlayerSettings)
|
||||||
|
|
|
||||||