Compare commits

...
172 Commits
Author SHA1 Message Date
js6pak b9e8def90d Switch to github actions (#492) 2022-09-01 19:28:41 +00:00
miniduikboot dc530406c6 Move config files to API
This makes it possible to access these from a plugin
2022-08-29 20:57:16 +02:00
miniduikboot 2de08da14d Add documentation for the compatibility options 2022-08-29 20:57:16 +02:00
miniduikboot 7a89e963dd Add unsupported option to allow future versions 2022-08-29 20:57:16 +02:00
miniduikboot 8aaf75e381 Make version mixing configurable 2022-08-29 20:57:16 +02:00
miniduikboot 59cb4a18e8 Prevent players joining game on different versions
Now that our game version compatibility list is growing longer with
every game patch, we need a way to make sure people in a game run the
same version of the game. Mismatching game version can lead to weird
issues, especially if mods are involved.
2022-08-29 20:57:16 +02:00
miniduikboot a0b5228e71 Improve setup documentation (#485)
- .NET download link was broken
- They also renamed their packages slightly, so update wording
- Add a note on port forwarding
- Add a note on setting up the region file
2022-08-29 20:56:34 +02:00
miniduikboot 78351c1dbe Add Chat Language to game listings (#491)
This was added to the in 6.23 patch
2022-08-28 17:04:35 +02:00
miniduikboot 45e0162c1a Add new client version (#489) 2022-08-23 20:59:45 +02:00
miniduikboot fcf8d66266 Allow spawning fake players (#488)
This is used by some mods to implement roles for unmodded clients
2022-07-24 19:25:13 +02:00
miniduikboot 6b6fa08125 Version bump for 2022.6.21 (#486)
Mostly untested, ran through a few games and seems to work fine
2022-06-22 21:36:58 +02:00
AeonLucid cea3d8980f Update appveyor.yml, replace NuGet auth token 2022-06-12 02:33:43 +03:00
js6pak d1ffdb95e1 Update appveyor.yml
crappveyor
2022-06-11 15:41:48 +00:00
miniduikboot 4d11cf91ad Remove Auth- and AnnouncementsServer sections (#484) 2022-06-03 18:58:00 +00:00
miniduikboot 84aba52198 Remove 75% of the question marks of PR #481 (#482) 2022-06-03 18:57:47 +00:00
js6pakandminiduikboot 6e4bb71289 Add Serilog.Settings.Configuration (#468)
* Add Serilog.Settings.Configuration

* Add docs section for logging

* Elaborate Serilog documentation

Co-authored-by: miniduikboot <mini@duikbo.at>
2022-06-03 20:31:52 +02:00
js6pak 8fec1a211e Merge pull request #483 from js6pak/fix-disconnect-reason
Fix non custom disconnect reasons
2022-06-03 20:31:10 +02:00
js6pak 85a2fce6c1 Fix non custom disconnect reasons 2022-06-03 20:17:59 +02:00
miniduikboot 224fdd1d5b Allow adding custom tasks on standard maps (#481)
This is needed for mods that add tasks to standard maps, but also mods
that add custom maps: because their custom netobjects don't get
registered Impostor thinks people are still on the old map when people
switch to the custom map after playing a game.
2022-05-25 19:53:32 +02:00
miniduikboot 380ba46f11 Upgrade to .NET 6 (#479)
* Upgrade to .NET 6

.NET 5 has gone EOL, so move to a supported version.

* Upgrade Docker container as well
* Update docs for .NET 6
* Re-add hack for System.IO.Pipelines
* Bump dependency versions
* Update the deps of the other projects too
* Only declare TargetFramework once
* Dockerfile: also copy over Directory.Build.props
* Cake: pick up target framework automatically
* Upgrade Cake as well
2022-05-25 19:52:22 +02:00
miniduikboot aeefc40ef1 Merge pull request #474 from SubmergedAmongUs/master
Add handling for null ShipStatus
2022-04-20 18:49:37 +02:00
AlexejheroYTB 743b8ed5cb Remove null check for ShipStatus known to not be null 2022-04-20 08:07:59 +03:00
AlexejheroYTB ed008872f6 Add handling for null ShipStatus 2022-04-16 17:11:58 +03:00
js6pak 4797d899af Merge pull request #471 from Impostor/feature/2022.3.29 2022-04-09 12:42:51 +00:00
js6pak c834013bd3 Simplify Message07JoinedGameS2CPre20220202 2022-04-07 16:58:33 +02:00
js6pak 70c180fb19 Make GameOptionsData de/serialization less confusing 2022-04-07 11:58:16 +02:00
miniduikboot 729368d777 Do not add ProductUserId/Friendcode on <2.24
Because it is fine to add data to the end of messages the new fields
could be added to Message 1 just fine, but because Message 7 contains a
loop, we need to send a different message to old clients there.
2022-04-05 20:05:06 +02:00
miniduikboot 5c06d1dd4d fixup! Add empty ProductUserId and FriendCode to packets 2022-04-05 19:52:25 +02:00
miniduikboot 446e5b8705 Add empty ProductUserId and FriendCode to packets
They are not sent to the server and no clue how to retrieve them out of band.
2022-04-05 19:52:25 +02:00
miniduikboot ae00ff9295 Barebones port 2022-04-05 19:52:25 +02:00
miniduikboot 400592b99c Merge pull request #467 from miniduikboot/fix/race-dc-send-all-except
Do not broadcast messages to disconnected clients
2022-03-26 10:35:54 +01:00
miniduikboot 9906c409da Do not broadcast messages to disconnected clients
This method is used when players have disconnected. If multiple players
disconnect at once, this method leads to exceptions.
2022-03-17 21:35:08 +01:00
miniduikboot c26d03a8bc Merge pull request #464 from miniduikboot/fix/custom-dc-msg
Fix/custom dc msg
2022-02-28 18:04:47 +01:00
miniduikboot ca48d672d5 Reword obsoletion message 2022-02-26 20:33:02 +01:00
miniduikboot 0b431dc5fa Change DisconnectAsync to use extension instead 2022-02-26 20:31:45 +01:00
miniduikboot 0b0c8274aa Turn DisconnectConnection into an extension 2022-02-26 20:31:23 +01:00
miniduikboot 36f8255e26 Fixup 608414326d
Oops, I accidentally forgot to remove the previous line when adding the
file to my commit
2022-02-26 19:08:57 +01:00
miniduikboot 919b094018 Deprecate JoinGame errors
Starting from version 2021.11.9, join errors no longer exist, instead a
client will show the message "An unknown error disconnected you from the
server". As a workaround, the connection is disconnected entirely when
an error occurs, which allows us to show a custom message.
2022-02-26 19:08:57 +01:00
js6pak 6125fd7006 Merge pull request #465 from miniduikboot/fix/2-28-bump 2022-02-26 17:26:54 +01:00
miniduikboot a3c0c8cacf Bump network version 2022-02-25 07:05:22 +01:00
miniduikboot b252bf2ee7 Merge pull request #460 from miniduikboot/feature/queryplatformids
Add QueryPlatformIds
2022-02-14 22:12:47 +01:00
miniduikboot 9b5a63e030 Add QueryPlatformIds
Some platforms (notable the Microsoft Store version) ask for this before connecting.
2022-02-02 22:17:47 +01:00
miniduikboot 6a8f089576 Merge pull request #455 from miniduikboot/fix/i18n-nicknames
Fix/i18n nicknames
2022-01-27 19:23:30 +01:00
miniduikboot d994323083 Merge pull request #458 from miniduikboot/fix/ac-engineer-snapto
AC: Allow engineers to move to a different vent.
2022-01-27 19:22:59 +01:00
miniduikboot 3f374da44b Partial revert of cc8d5d2: Readd length check
Oversized nicknames can cause bigger issues, so it is desireable to
still block them. .Length counts codepoints, not bytes, which means
that 10 character Japanese nicknames, which are configurable ingame,
should still be allowed.
2022-01-27 18:24:02 +01:00
miniduikboot bfd2efa716 AC: Allow engineers to move to a different vent. 2022-01-27 18:10:46 +01:00
miniduikboot 6867dec7ee Merge pull request #453 from miniduikboot/fix/ga-half-cooldown
AC CheckMurder: Require half of cooldown
2022-01-14 23:06:28 +01:00
miniduikboot 7132dc2d38 Add comment to clarify why this exists 2022-01-14 19:47:58 +01:00
miniduikboot 682bfac558 Merge pull request #452 from miniduikboot/fix/host-migrate
Before this commit, when the host of a game disconnects, the InnerPlayerInfo from the player is removed, which causes the new host to disconnect because of a deserialization error. This PR fixes this issue
2022-01-14 18:21:16 +01:00
miniduikboot cc8d5d2a45 Remove name length/validity checks from JoinGame
Length and validity are checked also checked by the anticheat. In case
Impostor goes out of sync with the allowed characters again, this can
just be fixed by disabling the Anticheat.

Check for NullOrWhiteSpace is kept because an empty username could be annoying
2022-01-10 20:54:45 +01:00
miniduikboot e6a35344c3 Sync IsCharAllowed with Innersloth implementation 2022-01-10 20:54:45 +01:00
miniduikboot db52b48cd6 AC CheckMurder: Require half of cooldown
When the Guardian Angel protects a player, the impostor that just missed
their kill gets back half of their cooldown. Keeping track of whether or
not the player was protected is more difficult due to how the Guardian
Angel is implemented, so instead we halve the minimum time between kill
in order to minimize false positives.
2022-01-08 19:20:11 +01:00
miniduikboot 50a526a02d Clamp taskCount to the length of the task list
New tasks cannot be created at this point because we don't know the
underlying tasks. So we try to maintain the tasks we do know of.
2022-01-08 17:42:05 +01:00
miniduikboot 608414326d Do not destroy PlayerControl if game is starting
This player may still get assigned tasks, which could lead to
deserialization problems.
2022-01-08 17:41:52 +01:00
miniduikboot d8bcb52c90 Mark game as started when RPC SetRole is called
This used to be done when SetInfected was called, but this RPC is no
longer used since 2021.11.9 in favor of this RPC.
2022-01-08 17:41:14 +01:00
miniduikboot d7d7547182 Merge pull request #442 from Impostor/2021.11.9
2021.11.9 and 2021.12.14 support
2021-12-21 23:27:38 +01:00
js6pak 64e27c3e21 Set RoleType in PlayerInfo.Deserialize 2021-12-15 15:36:01 +01:00
js6pak a0b433500c Don't do public methods in interfaces 2021-12-15 15:35:46 +01:00
js6pak c51a1f9c1f Readd HandleSet{Pet/Hat/Skin} 2021-12-15 15:33:01 +01:00
js6pak e15ac51dcf Implement cosmetic rpc methods 2021-12-15 15:22:18 +01:00
js6pak bde3a22f6e Document IClient.PlatformSpecificData 2021-12-15 14:52:22 +01:00
js6pak 6118e6b7b8 Change RoleOptionsData floats to be bytes as they can't ever be floats anyway 2021-12-15 14:51:07 +01:00
miniduikboot 32ecfedfba Add initial support for 2021.12.14 2021-12-14 21:38:26 +01:00
miniduikboot b6fe79cc8b Add RPC's for CheckProtect and ProtectPlayer 2021-11-22 23:04:56 +01:00
miniduikboot aeaffc849a Implement new MurderPlayer logic
In 2021.11.9, the host now uses MurderPlayer instead of impostors.
Impostor now use CheckMurder to request the host to kill a player. This
allows the host to prevent the target of the Guardian Angel from dying.

However, if the impostor that is checking the kill is also the host, AU
internally processes the CheckMurder RPC and sends the MurderPlayer RPC
first, *then* it sends the CheckMurder RPC.
2021-11-22 22:12:34 +01:00
miniduikboot a15f1b6a4c Add platform data to GameList 2021-11-15 22:55:57 +01:00
js6pak afb7051218 Fix ServerReplay 2021-11-13 19:51:52 +01:00
miniduikboot 8a0e9e876e Bump to 1.7 2021-11-12 23:12:47 +01:00
miniduikboot 22f1d74cdf Allow Shapeshifters to use RPC Shapeshift 2021-11-12 23:12:47 +01:00
miniduikboot e6d38f4b72 Allow Engineers to vent 2021-11-12 22:57:29 +01:00
miniduikboot 93c80c1412 Implement Rpc 44: SetRole 2021-11-12 22:56:35 +01:00
miniduikboot c3e0157209 Add name/psd/level to JoinGame- and JoinedGameS2C
Two players can now connect to the same lobby
2021-11-12 21:11:48 +01:00
miniduikboot 0769752407 Remove initial state flag from InnerGameData 2021-11-10 23:04:21 +01:00
miniduikboot fba1a894cc Implement SetActivePodType 2021-11-10 21:23:00 +01:00
js6pak 4d1aec9070 WIP 2021-11-10 20:46:56 +01:00
js6pak e0c7086973 RIP AnnouncementsServer 2021-11-10 13:52:15 +01:00
js6pak 125da11d61 [skip ci] Auto deploy github releases 2021-08-05 14:24:51 +02:00
js6pak d86efc1345 Merge pull request #431 from miniduikboot/feature/2021.6.30 2021-07-30 20:41:57 +02:00
js6pak 301a851ec3 Handle all handshake versions 2021-07-27 17:42:11 +02:00
js6pak 86c27402e2 Language and chat mode api 2021-07-27 16:59:09 +02:00
miniduikboot c63eb3b2d1 Improve docs (#435) 2021-07-25 19:53:43 +00:00
miniduikboot a1dac9f8b7 Address feedback 2021-07-25 20:22:02 +02:00
miniduikboot 3065e8df48 Check client version when parsing C2S handshake
2021.6.30 added new fields, which aren't present on old clients.

This commit makes sure players on old versions are disconnected properly
instead of the server erroring internally.
2021-07-21 21:53:22 +02:00
miniduikboot dc52e478dc Disable ownership check for BootFromVent 2021-07-21 20:46:33 +02:00
miniduikboot eb86c3c683 Implement RPC 35: Update System 2021-07-21 20:46:33 +02:00
miniduikboot e7c83769ef Implement RPC 34: Boot from vent 2021-07-21 20:46:33 +02:00
miniduikboot c6b8066794 Bump to 1.6 because new net version 2021-07-21 20:46:33 +02:00
miniduikboot 1ec5a050ad Add Vent Cleaning task
As these spawn in various rooms under the same task id the name of this
task does not include a room name
2021-07-21 20:46:33 +02:00
miniduikboot 1e7d132f31 Add Airship Lounge/Showers Empty Garbage tasks
Also Calibrate Distributor moved up
2021-07-21 20:46:33 +02:00
miniduikboot 9543134ef3 Add two extra fields to handshake 2021-07-21 20:46:33 +02:00
miniduikboot 389c72caa6 Bump client version 2021-07-21 20:46:33 +02:00
miniduikbootandjs6pak 66b4d860a9 Improve error when client version is unsupported (#432)
* Improve error when client version is unsupported

In the default message that was used previously the user is asked to
upgrade his game. This is not always correct, as sometimes the Impostor
server is too old and should be updated instead. Therefore custom
disconnect messages are used that blames either the user or the server
operator, which is hopefully more accurate.

I've chosen not to include the game version that is supported by the
server in this message because the network version rarely matches the
advertised version in the main menu.

* Rewrite versionCompare switch case

Co-authored-by: js6pak <kubastaron@hotmail.com>

Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-07-13 22:48:24 +02:00
js6pak dca26cff59 Log unsupported version 2021-07-07 19:01:48 +02:00
js6pak 3437c86bff Merge pull request #430 from Bramux/fix-hat-mismatch
Fix mismatched hats
2021-07-05 23:19:30 +02:00
Bramux 66fb8426a6 Correct hat mismatches 2021-07-05 22:26:28 +02:00
js6pak 4c839e2dd8 Merge pull request #429 from miniduikboot/fix/style 2021-07-05 21:22:28 +02:00
js6pak c6aa596e3b Fix warnings in Impostor.Benchmarks 2021-07-05 21:13:56 +02:00
miniduikboot d8843db3eb Use var instead of explicit type
Also prevent future issues
2021-07-05 20:36:56 +02:00
miniduikboot b918f25443 Remove unnecessary imports
And add rule to prevent future issues
2021-07-05 20:36:56 +02:00
js6pak 824359f93b Merge pull request #428 from miniduikboot/fix/colortype
Correct ColorType array
2021-07-05 20:33:11 +02:00
js6pak 046d09b5fa Merge pull request #427 from miniduikboot/fix/airship-spawn
Stop cancelling initial Airship spawn SnapTo RPC
2021-07-05 20:30:12 +02:00
miniduikboot 5410c71280 Correct ColorType array
When creating this array for the update, I used the wrong array. Oops!
Turns out 5 of these colors aren't actually in the game.
2021-07-05 20:06:21 +02:00
miniduikboot 241e867343 Stop cancelling initial Airship spawn SnapTo RPC
This is used to hide players that are still selecting their spawn
location. If this is cancelled, players are left standing at the
location they were at when the last meeting was called, which is undesirable.
2021-07-05 20:01:20 +02:00
js6pak 11f2ffd24d Remove legacy regionInfo patcher 2021-07-05 18:27:59 +02:00
js6pak 9df01d2cf7 Merge pull request #423 from miniduikboot/feature/2021.6.15 2021-06-26 20:26:07 +00:00
miniduikboot d2720442e9 Turn derived properties into getters
There is no significant performance difference: while accessing the
getters is slightly slower, this can be balanced against the cost of
setting the property. As this is also cleaner, switch to getters.
2021-06-25 18:46:28 +02:00
miniduikboot ddedffd121 Refactor Polus meeting room spawning logic
Also adjust the constants to the new constants used in game
2021-06-25 18:46:28 +02:00
miniduikboot 2f04f6ea98 Stub implementation of SendQuickChat
Proper API will follow later
2021-06-25 18:46:28 +02:00
miniduikboot 5f4c40bf36 Remove the table from the Readme
As Among Us is getting a lot of small network-compatible bugfix releases
nowadays, it doesn't seem necessary to maintain the table anymore.
Release notes state clearly which network version is supported and there
is limited support for old versions anyway.
2021-06-25 18:46:28 +02:00
miniduikboot ef4cc5646b Simplify the setup instructions
The patcher has not been updated to support the new JSON format and is
less necessary now that JSON is used for the region file format.

The website also now has deeplinking support, so we point Android/iOS
people to the website now too as that is more convenient compared to the
previous methods.
2021-06-25 18:46:28 +02:00
js6pak d894e9adc3 Meeting changes 2021-06-25 18:46:28 +02:00
js6pak c086cf80b1 Announcements protocol changes 2021-06-25 18:46:28 +02:00
js6pak 1118a59167 Update GameKeywords 2021-06-25 18:46:28 +02:00
miniduikboot 5154dd9aa5 Adjust Polus Meeting table spawn locations 2021-06-25 18:46:28 +02:00
miniduikboot a621225fcd Add new colors 2021-06-25 18:46:28 +02:00
miniduikboot 73a5463848 Update supported GameVersions 2021-06-25 18:46:28 +02:00
miniduikboot 02d25a290f Bump version because new net version 2021-06-15 22:20:07 +02:00
ced530b83a Added player voted event (#181)
Co-authored-by: AeonLucid <aeonlucid@outlook.com>
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-06-11 12:33:38 +00:00
8f1cba8429 Using MapData for Tasks (#395)
Co-authored-by: John Tran <john.tran.84@live.com.au>
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-06-10 18:54:34 +00:00
js6pak 9009bac883 Merge pull request #417 from miniduikboot/fix/initialize-color 2021-06-10 18:38:17 +00:00
miniduikboot f3460f05bc Initialize Color to -1 instead of Red
This could lead to an AC disconnect if the host picked red and waited
for other players to rejoin before joining back himself. Before this
commit, the host would SetColor himself to Red, but this would be
flagged as all other players would have been set to Red as enums
initialize to 0 (= Red) by default.

After the host SetColor'd himself, the host will send over the color
array, which initializes player colors to -1. This commit follows AU by
also initializing the color to -1, preventing the AC from flagging the
duplicate colors.
2021-05-30 18:30:47 +02:00
miniduikboot a13fee108f Fix KeyNotFoundException for nonexistent vents (#413)
Some mods add extra vents that don't yet exist, this commit checks if a
given vent exists and if it doesn't, throw an AC violation instead of
disconnecting the player

One downside is that the Enter/ExitVent events are no longer called, but
this would require the vent in that event to become nullable
2021-05-17 17:13:54 +00:00
js6pak adc0e6fe9b Don't broadcast packets of kicked players 2021-05-12 18:49:20 +02:00
js6pak ce62815dc5 Add custom message support (#404) 2021-05-10 11:08:26 +00:00
js6pak b1a0adaa28 Merge pull request #389 from Impostor/plugin-info-from-csproj 2021-04-27 17:54:53 +00:00
js6pak fe697b1b63 Deprecate old ImpostorPluginAttribute constructor 2021-04-27 14:58:16 +02:00
js6pak 55e6d38f9f Merge pull request #400 from HarmHoog/skin-hat-types 2021-04-26 12:48:16 +00:00
cchudant b73a46ff56 [skip ci] Rename dev branch in Running-the-server.md (#402) 2021-04-26 12:47:03 +00:00
js6pak 901deeff59 Remove ownership check from InnerVoteBanSystem 2021-04-21 22:01:01 +02:00
Harm Hoogeveen f2126fd4c6 Add new skin types 2021-04-20 14:24:06 +02:00
Harm Hoogeveen 9aa6109b3a Add new hat types 2021-04-20 14:23:02 +02:00
js6pak e1a6fdda98 Make it possible to read plugin information from csproj attributes 2021-04-13 23:13:52 +02:00
Harm Hoogeveenandjs6pak 283f59b51f Allow plugins to set dependencies, softdependencies and loadbefores to determine the load order of plugins (#385)
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-04-13 20:28:24 +00:00
Minorusamaandjs6pak d47343df08 BeforeGameCreatedEvent (#266)
Co-authored-by: js6pak <kubastaron@hotmail.com>
2021-04-13 16:29:44 +00:00
js6pak 0bb5442a3a Merge pull request #387 from Impostor/murder-check-ping
Add simple ping toleration to murder player check
2021-04-13 15:17:20 +00:00
js6pak 7ac6c32b5d Set configuration's BasePath to CurrentDirectory 2021-04-13 11:29:08 +02:00
112batman fbd9f12f9e Add GameHostChange event (#277) 2021-04-12 20:53:14 +00:00
js6pak f43577b745 Add simple ping toleration to murder player check 2021-04-11 16:05:08 +02:00
js6pak a56eed2680 Use actual disconnect message in ClientBase#DisconnectAsync 2021-04-11 14:57:29 +02:00
js6pak f0434f071c Merge pull request #377 from Impostor/airship 2021-04-11 12:04:31 +00:00
js6pak 8d27016cb7 Fix xmldoc warnings 2021-04-10 23:00:34 +02:00
js6pak e941796a4c Bump version 2021-04-10 22:55:40 +02:00
js6pak 1d66f07906 Make vent data initialization much cleaner 2021-04-10 17:14:17 +02:00
js6pak 7764987f91 Specify enum values for Platforms 2021-04-09 23:51:50 +02:00
js6pak bfba4385fd Make PlayerVentEvent an actual PlayerVentEvent 2021-04-06 21:10:53 +02:00
js6pak f03e72206e Update example plugin 2021-04-06 20:51:06 +02:00
js6pak 304b4bb7bf Rework vent api 2021-04-06 20:51:06 +02:00
970f826dc8 Allow Android Versions (#375)
Co-authored-by: js6pak <kubastaron@hotmail.com>
Co-authored-by: John Tran <john.tran.84@live.com.au>
2021-04-06 18:50:50 +00:00
js6pak 4866a350f8 Implement airship spawning, closes #376 2021-04-04 23:27:39 +02:00
js6pak 13bddeb7bd Split ShipStatus to multiple classes, implement new door types 2021-04-04 23:27:39 +02:00
js6pak 225b56e71f Fix cheatcontext in ValidateImpostor calls 2021-04-04 23:27:39 +02:00
js6pak 60bf6b5f58 Fix namespaces 2021-04-04 23:27:39 +02:00
b5cee48242 Airship Vent Enums (#373)
Co-authored-by: miniduikboot <5243971+miniduikboot@users.noreply.github.com>
Co-authored-by: John Tran <john.tran.84@live.com.au>
2021-04-04 10:31:28 +00:00
js6pak c750c65481 Merge pull request #372 from miniduikboot/2021.3.31 2021-04-04 10:26:07 +00:00
miniduikboot d801a36af8 Rename things for 6pak 2021-04-04 10:35:00 +02:00
miniduikboot 441d9c300c Move PlayerVentEvent call to applicable RPC's 2021-04-03 00:46:34 +02:00
miniduikboot 7fd68e31e6 Fix Docker container build 2021-04-03 00:37:12 +02:00
miniduikboot 47aebe7b7b Fix InnerShipStatus deserializing
3.31 now distributes them as multiple messages

This also explains the two weird bytes in HeliSabotage, so these can be
removed too
2021-04-03 00:29:05 +02:00
miniduikboot 66c2434320 Implement HeliSabotageSystemType
It works, although I'm not completely sure why.
2021-04-03 00:29:05 +02:00
miniduikboot c01062ed65 implement rpc 32: use platform 2021-04-03 00:29:05 +02:00
miniduikboot d5ae007d1c implement rpc 31: climb ladder 2021-04-03 00:29:05 +02:00
miniduikboot 16a2b0aac6 I counted the doors on Airship
and I hope I counted correctly
2021-04-03 00:29:05 +02:00
miniduikboot 4c1bd4a578 editorconfig: Don't indent blocks in case contents
This is more in line with the existing codebase
2021-04-03 00:29:05 +02:00
miniduikboot d311150967 API: update enums for airship 2021-04-03 00:29:05 +02:00
miniduikboot 92e3506f51 First attempt at getting some airship stuff online 2021-04-03 00:29:05 +02:00
miniduikboot a63fc40099 Gamedata packets are now have initial state false
I managed to get into a lobby with this
2021-04-03 00:29:05 +02:00
js6pak 4f53d3f4e6 Hopefully fix the submodule 2021-04-03 00:14:33 +02:00
js6pak a39fae3325 Initial auth implementation 2021-04-03 00:12:15 +02:00
js6pak 7c34836d50 Remove reactor stuff 2021-04-03 00:12:15 +02:00
js6pak 989b06d04c Use BitConverter.Int32BitsToSingle in SpanReaderExtensions 2021-04-03 00:12:15 +02:00
js6pak 11e87e51db Update airship constants 2021-04-03 00:12:15 +02:00
js6pak b90e5b2c88 Switch back hazel to submodule 2021-04-03 00:11:55 +02:00
313 changed files with 10105 additions and 9384 deletions

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"cake.tool": {
"version": "1.1.0",
"version": "2.2.0",
"commands": [
"dotnet-cake"
]
+57
View File
@@ -0,0 +1,57 @@
name: CI
on:
push:
paths:
- '.github/workflows/ci.yml'
- 'src/**/**'
- '.gitmodules'
- 'build.cake'
pull_request:
paths:
- '.github/workflows/ci.yml'
- 'src/**/**'
- '.gitmodules'
- 'build.cake'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- uses: actions/cache@v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.x
- name: Run the Cake script
uses: cake-build/cake-action@v1
with:
verbosity: Diagnostic
- uses: softprops/action-gh-release@v1
if: github.ref_type == 'tag'
with:
draft: true
files: |
./build/*.zip
./build/*.tar.gz
./build/*.nupkg
./build/*.snupkg
- name: Push NuGet package
if: github.ref_type == 'tag'
run: |
dotnet nuget push ./build/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_IMPOSTOR }}
+3
View File
@@ -0,0 +1,3 @@
[submodule "src/Impostor.Hazel"]
path = src/Impostor.Hazel
url = https://github.com/Impostor/Impostor.Hazel
+3 -3
View File
@@ -9,14 +9,14 @@ We are always looking for people to help improve Impostor.
- Don't commit unnecessary changes to the codebase or debugging code.
- Write meaningful commits or squash them.
- Please try to follow the code style of the rest of the codebase. An `.editorconfig` file has been provided to keep consistency.
- Stylecop is also enabled: please make sure your PR compiles without warnings.
## Pull requests
- Only make pull requests to the `dev` branch.
- Only implement one feature per pull request to keep it easy to understand.
- Expect comments or questions on your pull request from the project maintainers. We try to keep the code as consistent and maintainable as possible.
- Each pull request should come from a new branch in your fork, it should have a meaningful name.
- Each pull request should come from a new branch in your fork, it should have a meaningful name.
- We try to respond to pull requests as fast as possible. If you think we might have missed it, let us know on [Discord](https://discord.gg/Mk3w6Tb).
If you have any questions, let us know.
If you have any questions, let us know.
+6 -5
View File
@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:5.0 AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:6.0 AS build
# See for all possible platforms
# https://github.com/containerd/containerd/blob/master/platforms/platforms.go#L17
@@ -11,7 +11,8 @@ WORKDIR /source
# Copy csproj and restore.
COPY src/Impostor.Server/Impostor.Server.csproj ./src/Impostor.Server/Impostor.Server.csproj
COPY src/Impostor.Api/Impostor.Api.csproj ./src/Impostor.Api/Impostor.Api.csproj
COPY src/Impostor.Hazel/Impostor.Hazel.csproj ./src/Impostor.Hazel/Impostor.Hazel.csproj
COPY src/Impostor.Hazel/Hazel/Hazel.csproj ./src/Impostor.Hazel/Hazel/Hazel.csproj
COPY src/Directory.Build.props ./src/Directory.Build.props
RUN case "$TARGETARCH" in \
amd64) NETCORE_PLATFORM='linux-x64';; \
@@ -21,7 +22,7 @@ RUN case "$TARGETARCH" in \
esac && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Server/Impostor.Server.csproj && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Api/Impostor.Api.csproj && \
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Impostor.Hazel.csproj
dotnet restore -r "$NETCORE_PLATFORM" ./src/Impostor.Hazel/Hazel/Hazel.csproj
# Copy everything else.
COPY src/. ./src/
@@ -35,8 +36,8 @@ RUN case "$TARGETARCH" in \
dotnet publish -c release -o /app -r "$NETCORE_PLATFORM" -p:VersionSuffix="$VERSIONSUFFIX" --no-restore ./src/Impostor.Server/Impostor.Server.csproj
# Final image.
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime:5.0
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime:6.0
WORKDIR /app
COPY --from=build /app ./
EXPOSE 22023/udp
ENTRYPOINT ["./Impostor.Server"]
ENTRYPOINT ["./Impostor.Server"]
+7 -36
View File
@@ -1,15 +1,13 @@
# Impostor
[![Discord](https://img.shields.io/badge/Discord-chat-blue?style=flat-square)](https://discord.gg/Mk3w6Tb)
[![AppVeyor](https://img.shields.io/appveyor/build/Impostor/Impostor/master?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master)
[![CI](https://github.com/Impostor/Impostor/workflows/CI/badge.svg)](https://github.com/Impostor/Impostor/actions)
Impostor is one of the first **Among Us** private servers, written in C#.
Impostor is the first working **Among Us** private server, written in C#.
| Impostor version | Among Us version | Experimental | Download |
|-|-|-|-|
| 1.1.0 | 2020.09.07 - 2020.09.22 | No | [![Download](https://img.shields.io/badge/Download-v1.1.0-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.1.0) |
| 1.2.2 | 2020.09.22 - 2020.11.17 | No | [![Download](https://img.shields.io/badge/Download-v1.2.2-blue?style=flat-square)](https://github.com/Impostor/Impostor/releases/tag/v1.2.2) |
| 1.3.0 | 2021.3.5 | Yes | [![Download](https://img.shields.io/badge/Download-master-blue?style=flat-square)](https://ci.appveyor.com/project/Impostor/Impostor/branch/master/artifacts) |
As Among Us is actively updated, you may want to use the latest build from the master branch if you want to play on the latest version of Among Us that supported by Impostor.
If you want to play on an older version of Among Us, you can download old releases from [here](https://github.com/Impostor/Impostor/releases/), however these versions are less supported.
## Features
@@ -21,34 +19,7 @@ Impostor is one of the first **Among Us** private servers, written in C#.
### Client
If you just want to play on a server hosted by someone else, you need to follow these instructions.
#### Windows
1. Find the [latest release](https://github.com/AeonLucid/Impostor/releases/latest).
2. Download `Impostor-Patcher-win-x64.zip`.
3. Extract the zip.
4. Run `Impostor.Patcher.exe`.
5. Follow the instructions inside the application.
![Client](docs/images/client.jpg)
If you do not wish to execute any programs. Follow the instructions in [this website](https://impostor.github.io/Impostor)
#### Android
##### Android 10 and below.
1. Go to [this website](https://impostor.github.io/Impostor) **(ON YOUR MOBILE DEVICE)**
2. Follow the instructions listed there.
##### Android 11.
1. Connect your phone to a computer. Go to [this website](https://impostor.github.io/Impostor) on the computer and follow the steps 1 and 2 to generate a `regionInfo.dat` file.
2. Instead of following the next steps, open the phone's internal storage on your computer and navigate to `/sdcard/Android/data/com.innersloth.spacemafia/files`.
3. Copy the generated `regionInfo.dat` file into the `files` folder you just navigated to.
#### iOS
iOS devices need to be jailbroken in order to connect to Impostor servers.
If you just want to play on a server hosted by someone else, you need to configure your client to connect to an Impostor server. Please go to [this website](https://impostor.github.io/Impostor) to set up your client by following the instructions for your OS there.
### Server
@@ -56,7 +27,7 @@ See the [docs](docs/Running-the-server.md) for instructions on how to set it up.
## Troubleshooting
See [TROUBLESHOOTING](docs/TROUBLESHOOTING.md) to solve issues the Impostor client or the server.
See [TROUBLESHOOTING](docs/TROUBLESHOOTING.md) to solve issues with the Impostor client or the server.
## Contributing
-50
View File
@@ -1,50 +0,0 @@
version: '{build}'
environment:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
branches:
except:
- gh-pages
pull_requests:
do_not_increment_build_number: true
assembly_info:
patch: false
dotnet_csproj:
patch: false
image: Ubuntu2004
install:
- git submodule update --init --recursive
- ps: dotnet tool restore
build_script:
- ps: dotnet cake build.cake --bootstrap
- ps: dotnet cake build.cake --pack
test: off
artifacts:
- path: ./build/*.zip
- path: ./build/*.tar.gz
- path: ./build/*.nupkg
- path: ./build/*.snupkg
# deploy:
# - provider: NuGet
# artifact: /.*(\.|\.s)nupkg/
# on:
# branch: dev
# api_key:
# secure: 4OHXl+m1KVi60hB1j54MpdP8tVv0UNfkdF4rVP+2AhAjN4a2MVT+Bl90gJZ96xHF
only_commits:
files:
- appveyor.yml
- build.cake
- src/**/*
- .gitmodules
+39 -35
View File
@@ -1,25 +1,33 @@
#addin "nuget:?package=SharpZipLib&Version=1.3.1"
#addin "nuget:?package=Cake.Compression&Version=0.2.6"
#addin "nuget:?package=Cake.FileHelpers&Version=4.0.1"
#addin "nuget:?package=SharpZipLib&Version=1.3.3"
#addin "nuget:?package=Cake.Compression&Version=0.3.0"
#addin "nuget:?package=Cake.FileHelpers&Version=5.0.0"
var workflow = BuildSystem.GitHubActions.Environment.Workflow;
var buildId = workflow.RunNumber;
var tag = workflow.RefType == GitHubActionsRefType.Tag ? workflow.RefName : null;
var buildId = EnvironmentVariable("GITHUB_RUN_NUMBER") ?? EnvironmentVariable("APPVEYOR_BUILD_VERSION");
var buildRelease = EnvironmentVariable("APPVEYOR_REPO_TAG") == "true";
var buildVersion = FindRegexMatchGroupInFile("./src/Directory.Build.props", @"\<VersionPrefix\>(.*?)\<\/VersionPrefix\>", 1, System.Text.RegularExpressions.RegexOptions.None).Value;
var buildDir = MakeAbsolute(Directory("./build"));
var target = Argument("target", "Deploy");
var target = Argument("target", "Test");
var configuration = Argument("configuration", "Release");
var msbuildSettings = new DotNetCoreMSBuildSettings();
var msbuildSettings = new DotNetMSBuildSettings();
if (buildRelease)
if (tag != null)
{
msbuildSettings.Properties["Version"] = new[] { buildVersion };
if (tag[1..] != buildVersion) throw new Exception("Tag version has to be the same as VersionPrefix in Directory.Build.props");
msbuildSettings.Version = buildVersion;
}
else if (buildId != null)
else if (buildId != 0)
{
msbuildSettings.Properties["VersionSuffix"] = new[] { "ci." + buildId };
buildId += 500;
msbuildSettings.VersionSuffix = "ci." + buildId;
buildVersion += "-ci." + buildId;
}
else
{
buildVersion += "-dev";
}
//////////////////////////////////////////////////////////////////////
@@ -31,10 +39,9 @@ private void ImpostorPublish(string name, string project, string runtime, bool i
var projBuildDir = buildDir.Combine(name + "_" + runtime);
var projBuildName = name + "_" + buildVersion + "_" + runtime;
DotNetCorePublish(project, new DotNetCorePublishSettings {
DotNetPublish(project, new DotNetPublishSettings {
Configuration = configuration,
NoRestore = true,
Framework = "net5.0",
Runtime = runtime,
SelfContained = false,
PublishSingleFile = true,
@@ -57,6 +64,10 @@ private void ImpostorPublish(string name, string project, string runtime, bool i
} else {
GZipCompress(projBuildDir, buildDir.CombineWithFilePath(projBuildName + ".tar.gz"));
}
if (BuildSystem.GitHubActions.IsRunningOnGitHubActions) {
BuildSystem.GitHubActions.Commands.UploadArtifact(projBuildDir, projBuildName);
}
}
private void ImpostorPublishNF(string name, string project) {
@@ -64,7 +75,7 @@ private void ImpostorPublishNF(string name, string project) {
var projBuildDir = buildDir.Combine(name + "_" + runtime);
var projBuildZip = buildDir.CombineWithFilePath(name + "_" + buildVersion + "_" + runtime + ".zip");
DotNetCorePublish(project, new DotNetCorePublishSettings {
DotNetPublish(project, new DotNetPublishSettings {
Configuration = configuration,
NoRestore = true,
Framework = "net472",
@@ -90,18 +101,17 @@ Task("Clean")
Task("Restore")
.Does(() => {
DotNetCoreRestore("./src/Impostor.sln");
DotNetRestore("./src/Impostor.sln");
});
Task("Replay")
.Does(() => {
// D:\Projects\GitHub\Impostor\Impostor\src\Impostor.Tools.ServerReplay\sessions
DotNetCoreRun(
DotNetRun(
"./src/Impostor.Tools.ServerReplay/Impostor.Tools.ServerReplay.csproj",
"./src/Impostor.Tools.ServerReplay/sessions", new DotNetCoreRunSettings {
"./src/Impostor.Tools.ServerReplay/sessions", new DotNetRunSettings {
Configuration = configuration,
NoRestore = true,
Framework = "net5.0"
});
});
@@ -111,16 +121,9 @@ Task("Build")
.IsDependentOn("Replay")
.Does(() => {
// Tests.
DotNetCoreBuild("./src/Impostor.Tests/Impostor.Tests.csproj", new DotNetCoreBuildSettings {
DotNetBuild("./src/Impostor.Tests/Impostor.Tests.csproj", new DotNetBuildSettings {
Configuration = configuration,
});
// Client.
ImpostorPublishNF("Impostor-Patcher", "./src/Impostor.Patcher/Impostor.Patcher.WinForms/Impostor.Patcher.WinForms.csproj");
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "win-x64");
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "osx-x64");
ImpostorPublish("Impostor-Patcher-Cli", "./src/Impostor.Patcher/Impostor.Patcher.Cli/Impostor.Patcher.Cli.csproj", "linux-x64");
// Server.
ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "win-x64", true);
@@ -130,32 +133,33 @@ Task("Build")
ImpostorPublish("Impostor-Server", "./src/Impostor.Server/Impostor.Server.csproj", "linux-arm64", true);
// API.
DotNetCorePack("./src/Impostor.Api/Impostor.Api.csproj", new DotNetCorePackSettings {
DotNetPack("./src/Impostor.Api/Impostor.Api.csproj", new DotNetPackSettings {
Configuration = configuration,
OutputDirectory = buildDir,
IncludeSource = true,
IncludeSymbols = true,
MSBuildSettings = msbuildSettings
});
if (BuildSystem.GitHubActions.IsRunningOnGitHubActions) {
foreach (var file in GetFiles(buildDir + "/*.{nupkg,snupkg}"))
{
BuildSystem.GitHubActions.Commands.UploadArtifact(file, "Impostor.Api");
}
}
});
Task("Test")
.IsDependentOn("Build")
.Does(() => {
DotNetCoreTest("./src/Impostor.Tests/Impostor.Tests.csproj", new DotNetCoreTestSettings {
DotNetTest("./src/Impostor.Tests/Impostor.Tests.csproj", new DotNetTestSettings {
Configuration = configuration,
NoBuild = true
});
});
Task("Deploy")
.IsDependentOn("Test")
.Does(() => {
Information("Finished.");
});
//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////
RunTarget(target);
RunTarget(target);
+8 -15
View File
@@ -1,19 +1,20 @@
# Building from source
The solution contains two main projects, the Impostor server and patcher. The server is built using [.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0) and the winforms patcher is with [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472).
The solution contains the Impostor server and its dependencies, like Hazel and the plugin API. The server is built using [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0).
## Cloning Impostor
You need to clone Impostor using git.
You need to clone Impostor using git:
```bash
git clone https://github.com/AeonLucid/Impostor.git
git clone https://github.com/Impostor/Impostor.git
```
## Building the server
### Dependencies
- [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0)
- [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0)
- [Rider](https://www.jetbrains.com/rider/) or [Visual Studio](https://visualstudio.microsoft.com/vs/) (Optional, only if you want the full IDE experience)
### Build using the CLI
@@ -21,16 +22,8 @@ git clone https://github.com/AeonLucid/Impostor.git
```bash
cd src/Impostor.Server/
dotnet build
# Or if you want a single file, ready for production: (change linux-x64 to win-x64 if you use Windows)
dotnet publish -c Release -r linux-x64 -p:PublishSingleFile=true
```
To setup the server, please look at [Running the server](Running-the-server.md).
## Building the winforms patcher
### Dependencies
* [.NET Framework 4.7.2 Developer Pack](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net472-developer-pack-offline-installer) or [Mono](https://www.mono-project.com/download/)
### Build using the CLI
```bash
cd src/Impostor.Patcher/Impostor.Patcher.WinForms
dotnet build
```
+7 -3
View File
@@ -1,11 +1,15 @@
# Frequently Answered Questions
## What is this?
The Impostor project is a reverse engineered and open sourced server for the game Among Us. The game itself is developed by [InnerSloth](http://www.innersloth.com/) while this project is maintained by the community. This project was built out of frustration for the lack of server availability in certain regions and the inability for the core developer, [AeonLucid](https://github.com/AeonLucid), to join a public game. As of this time, it has not been officially endorsed by the studio.
The Impostor project is a reverse engineered and open source server for the game Among Us. The game itself is developed by [Innersloth](http://www.innersloth.com/) while this project is maintained by the community. This project was built out of frustration for the lack of server availability in certain regions and the inability for the core developer, [AeonLucid](https://github.com/AeonLucid), to join a public game. As of this time, it has not been officially endorsed by the studio.
## Can this be used with the mobile version of the game?
Yes, Impostor can be used with both the Android and iOS\* versions of the game.
###### \* In order to play on an Impostor server with iOS, you _must_ have a jailbroken device.
Yes, Impostor can be used with both the Android and iOS versions of the game. You can add a custom server via a link, you can do this using the [site](https://impostor.github.io/Impostor)
## How can I get started?
See [Setting up your Server](Running-the-server.md) for more information on running the server and [Client Setup](https://impostor.github.io/Impostor/) for helping your friends join in!
If you're having issues with the server software, check the [Troubleshooting page](TROUBLESHOOTING.md).
+20 -15
View File
@@ -1,30 +1,35 @@
# Running the server
There are currently two modes to run the Impostor server in. The first way is the simplest one and is the one you should probably use. The other way will distribute players across other servers and is a more advanced configuration.
There are currently two modes to run the Impostor server. The first way, Single Server, is the simplest one, can handle up to a few hundred simultaneous players, and is the one you should probably use. Multi-Server mode will distribute players across other servers and is intended for advanced users.
## Single server
### Without docker
1. Install the **.NET 5.0 runtime**.
- [Windows x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.0-windows-x64-installer)
- [Linux x64](https://docs.microsoft.com/en-us/dotnet/core/install/linux)
- [macOS x64](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-5.0.0-macos-x64-installer)
2. Find the [latest dev release](https://ci.appveyor.com/project/Impostor/Impostor/branch/dev/artifacts).
3. Download either the Windows or the Linux version.
### Without Docker
1. Install the [.NET 6.0 runtime](https://dotnet.microsoft.com/download/dotnet/6.0). Installing the SDK also works, but is not necessary unless you plan on developing Impostor or Impostor plugins. If you're asked to pick between the normal, desktop or server runtime, the normal runtime is enough, but some plugins may require the ASP.NET Core Runtime as well.
2. Find the [latest release](https://github.com/Impostor/Impostor/releases) or the [latest CI build](https://nightly.link/Impostor/Impostor/workflows/ci/master).
3. Download the version for your OS (linux/win/osx). Impostor is built for multiple CPU-architectures, you most likely want the x64 version, unless you are running on a Raspberry Pi or another device with an ARM processor.
4. Extract the zip.
5. Modify `config.json` to your liking. Documentation can be found [here](Server-configuration.md) *(this step is mandatory if you want to expose this server to other devices)*
6. Run `Impostor.Server.exe` (Windows) / `Impostor.Server` (Linux)
5. Modify `config.json` to your liking. Documentation can be found [here](Server-configuration.md) _(this step is mandatory if you want to expose this server to other devices)_
6. Run `Impostor.Server` (Linux/macOS) or `Impostor.Server.exe` (Windows)
### Using docker
Depending on your host you may also need to port forward Impostor to the internet. By default Impostor uses port **22023** and the **UDP** protocol. As port forwarding changes per host or router configuration, port forwarding is not covered by this guide.
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor?sort=semver)](https://hub.docker.com/repository/docker/aeonlucid/impostor)
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor/nightly)](https://hub.docker.com/repository/docker/aeonlucid/impostor)
To connect to the server, you need to configure a region file on https://impostor.github.io/Impostor/
### Using Docker
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor?sort=semver)](https://hub.docker.com/r/aeonlucid/impostor)
[![Docker Image](https://img.shields.io/docker/v/aeonlucid/impostor/nightly)](https://hub.docker.com/r/aeonlucid/impostor)
After installing Docker, you can just start a Docker container with `docker run`:
```
docker run -p 22023:22023/udp aeonlucid/impostor:nightly
```
### Using docker-compose
### Using Docker Compose
```
version: '3.4'
@@ -42,7 +47,7 @@ services:
## Multiple servers
Follow the steps from the single server on two or more servers.
Follow the steps from the single server on two or more servers. You should only need to set this up if you have a very large server and can no longer fit everyone on one server: if this is your first time installing Impostor, use a single server.
### Master server
+78 -42
View File
@@ -1,35 +1,92 @@
# Server configuration
Some information about all the possible configurations. Click [here](https://github.com/AeonLucid/Impostor/blob/master/src/Impostor.Server/config.full.json) to see all the possible config options.
Some information about all the possible configurations. Click [here](https://github.com/Impostor/Impostor/blob/master/src/Impostor.Server/config-full.json) to see all the possible config options.
## Options
### Required Server Configuration
| Key | Default | Description |
|-|-|-|
| **PublicIp** | `127.0.0.1` | This needs to the public IPv4 address of the server which you give to others to connect. You can find your IPv4 address [on this website](http://whatismyip.host/). Unless you are only planning to use Impostor privately, on your local network, you should change this to your public ip. It is also possible to use hostnames instead of IPv4 addresses, which will be resolved to IPv4 addresses. |
| **PublicPort** | `22023` | The public port of the server which you give to others to connect. (**This is the external port you configure on your router when port forwarding.**) Usually `22023`. |
| **ListenIp** | `0.0.0.0` | The network interface to listen on. If you do not know what to put here, use `0.0.0.0`. Since 1.2.2 it is also possible to use hostnames instead of IPv4 addresses, these must resolve to a valid IPv4 address. |
| **ListenPort** | `22023` | The listen port of the server, usually `22023`. |
| Key | Default | Description |
| -------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **PublicIp** | `127.0.0.1` | This needs to the public IPv4 address of the server which you give to others to connect. You can find your IPv4 address [on this website](http://whatismyip.host/). Unless you are only planning to use Impostor privately, on your local network, you should change this to your public ip. It is also possible to use hostnames instead of IPv4 addresses, which will be resolved to IPv4 addresses. |
| **PublicPort** | `22023` | The public port of the server which you give to others to connect. (**This is the external port you configure on your router when port forwarding.**) Usually `22023`. |
| **ListenIp** | `0.0.0.0` | The network interface to listen on. If you do not know what to put here, use `0.0.0.0`. Since 1.2.2 it is also possible to use hostnames instead of IPv4 addresses, these must resolve to a valid IPv4 address. |
| **ListenPort** | `22023` | The listen port of the server, usually `22023`. |
### AntiCheat
| Key | Default | Value |
|-|-|-|
| **Enabled** | `true` | Whether the anticheat should be enabled. |
| **BanIpFromGame** | `true` | When a player is caught hacking, they will be kicked from the server. If this value is set to `true`, the player will be banned instead and will not be able to rejoin that specific game. **(Setting this to false does not disable the anti-cheat!)** |
Impostor has an Anticheat that makes it possible to kick cheaters from games automatically. Note that the anticheat is tuned on the vanilla version of the game, so client-side modifications could trigger the Anticheat if you're playing with them.
| Key | Default | Value |
| ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Enabled** | `true` | Whether the anticheat should be enabled. |
| **BanIpFromGame** | `true` | When anticheat is enabled and a player is caught hacking, they will be kicked from the server. If this value is set to `true`, the player will be banned instead and will not be able to rejoin that specific game. |
### Compatibility
Impostor has two compatibility options which allow some extra flexibility but may not work properly. Enabling either of these options is not recommended.
| Key | Default | Value |
| ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **AllowNewGameVersions** | `false` | Warning: Setting this option to `true` is unsupported and may cause issues when large updates to Among Us are released. Allow future versions of Among Us to join your server. |
| **AllowVersionMixing** | `false` | Allow players using different game versions to play in one lobby. |
### Debug
The Debug configuration is used to enable the game recorder. This is mostly useful when developing Impostor.
| Key | Default | Value |
| ----------------------- | ------- | -------------------------------------------- |
| **GameRecorderEnabled** | `false` | Enables the Game Recorder. |
| **GameRecorderPath** | _empty_ | Path where the recorded games will be saved. |
### ServerRedirector
In a multi-node setup these need to be specified.
| Key | Default | Value |
|-|-|-|
| **Enabled** | `false` | Whether the server runs in multi-node setup. If this is `false`, all other options in this section do not have any effect. |
| **Master** | `false` | Whether the current server is a master. A master is responsible for redirecting clients to nodes |
| **Locator** | | Fill in either `Redis` or `UdpMasterEndpoint` to choose which method to use for locating other nodes. This must be the same across all servers. |
| **>Redis** | | Format `127.0.0.1.6379`, you can also use a password like so: `127.0.0.1.6379,password=value`. |
| **>UdpMasterEndpoint** | | On the master, this value acts as a listen ip and port. On a node, this should be the public ip and port of the master. Format `127.0.0.1:32320`. |
| **Nodes** | | An array containing public ips and ports of nodes. Only needs to be set on the master. See above for an example. |
In a multi-node setup these values need to be specified. Note that most people do not need to run a Multi-node setup.
| Key | Default | Value |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Enabled** | `false` | Whether the server runs in multi-node setup. If this is `false`, all other options in this section do not have any effect. |
| **Master** | `false` | Whether the current server is a master. A master is responsible for redirecting clients to nodes |
| **Locator** | | Fill in either `Redis` or `UdpMasterEndpoint` to choose which method to use for locating other nodes. This must be the same across all servers. |
| **>Redis** | | Format `127.0.0.1.6379`, you can also use a password like so: `127.0.0.1.6379,password=value`. |
| **>UdpMasterEndpoint** | | On the master, this value acts as a listen ip and port. On a node, this should be the public ip and port of the master. Format `127.0.0.1:32320`. |
| **Nodes** | | An array containing public ips and ports of nodes. Only needs to be set on the master. See above for an example. |
### Serilog (Logging)
Impostor's log framework, Serilog, can be configured in the config file. You can change its default log level and you can add additional sinks.
| Key | Default | Value |
| ---------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **MinimumLevel** | `Information` | Minimum log level for a message to be printed. If a log entry is as severe or more severe than this level, it will be printed. From most severe to least severe: `Fatal`,`Error`, `Warning`, `Information`, `Debug`, `Verbose` |
| **Using** | `[]` | List of additional Serilog Sinks assemblies to load. |
| **WriteTo** | `[]` | Additional logging sinks. See the Serilog documentation or the example in this section. Serilog |
For more information, check the [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration) documentation.
For example, to add logging to a file, you should add the following snippet to your configuration:
```json
"Serilog": {
"Using": [
"Serilog.Sinks.File"
],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "logs/log.txt",
"rollingInterval": "Day"
}
}
]
}
```
Next to that, you also need to copy over Serilog.Sinks.File.dll from [NuGet](https://www.nuget.org/packages/Serilog.Sinks.File/). See the [Serilog.Sinks.File documentation](https://github.com/serilog/serilog-sinks-file#json-appsettingsjson-configuration) for a list of parameters that can be configured.
Other Serilog sinks are also supported, but are out of scope for this documentation.
## Config providers
@@ -37,30 +94,9 @@ In a multi-node setup these need to be specified.
The simplest option to configure is by using the `config.json` file next to the server executable. For all possible options see the [config-full.json](https://github.com/Impostor/Impostor/blob/dev/src/Impostor.Server/config-full.json) file.
### Command line arguments
TODO
```
Server:PublicIp=127.0.0.1
Server:PublicPort=22023
Server:ListenIp=0.0.0.0
Server:ListenPort=22023
AntiCheat:Enabled=true
AntiCheat:BanIpFromGame=true
ServerRedirector:Enabled=false
ServerRedirector:Master=true
ServerRedirector:Locator:Redis=127.0.0.1.6379
ServerRedirector:Locator:UdpMasterEndpoint=127.0.0.1:32320
ServerRedirector:Nodes:0:Ip=127.0.0.1
ServerRedirector:Nodes:0:Port=22024
ServerRedirector:Nodes:1:Ip=127.0.0.1
ServerRedirector:Nodes:1:Port=22025
```
### Environment variables
TODO
If you're unable to edit the config.json file, you can instead set Environment variables to configure Impostor. The general pattern for each variable is `IMPOSTOR_SectionName__VariableName`. For example, to disable the anticheat, you can set the environment variable `IMPOSTOR_AntiCheat__Enabled=false`. Here are some more examples:
```
IMPOSTOR_Server__PublicIp=127.0.0.1
+38 -9
View File
@@ -1,28 +1,57 @@
# Troubleshooting
If you're reading this, something went wrong.
Don't worry though, as this is the most thorough guide to help you!
## `./Impostor.Server: line 1: ELF: not found` (plus other errors)
No idea where you got that system. But we clearly do **NOT** support it.
## `cannot execute binary file: Exec format error`
Please check that you have downloaded the right version of Impostor, as we mantain two CPU architectures (x64 and ARM).
Unless you are running Impostor on a SBC (Single-Board Computer), like the Raspberry Pi, you most likely want to use the x64 version.
Please check that you have downloaded the right version of Impostor, as we mantain two CPU architectures (x64 and ARM).
Unless you are running Impostor on a computer like the Raspberry Pi, you most likely want to use the x64 version.
## `./Impostor.Server: Permission denied`
This is an error related to Linux file permissions.
Some files do not hold their executable bit (the permission that allows them to run) during a download.
You can solve this by doing: `chmod +x Impostor.Server`
## `You are using an older version of the game`
You are using an older version of Impostor. The game does not really check who is outdated and blames it on the user.
Make sure you got the latest working version of Impostor (probably in AppVeyor, not Github).
## Disconnected with `Your client is too new, please update your Impostor to play`
## `You disconnected from the server. Reliable Packet 1 ...`
Please double-check that you have followed the [Server Configuration](Server-configuration.md) correctly.
**NOTE: Your public ip does not start with `127` nor `192`**
This happens when your game is too new for your copy of Impostor to support.
If you're using an Impostor release, check if there is a newer release available that supports your version. If this doesn't exist, you can try the [latest build from CI](https://nightly.link/Impostor/Impostor/workflows/ci/master).
If even that build doesn't work, you can try looking through the Pull Requests to see if there is a pending pull request that aims to update it to the next version, but note these may be unstable and may contain malicious code, as they haven't been vetted by the Impostor development team yet.
## Disconnected with `Please update your game to play on this server`
This happens when you're using a version of Impostor that is too new for your game version. You can download an older version from [the GitHub release page](https://github.com/Impostor/Impostor/releases). We however don't support older versions of Impostor with new API's and bugfixes so we recommend to update your game instead.
## Disconnected with `You are using an older version of the game`
You are using a version of Impostor that is not designed for the version of the game you're playing. The game does not really check who is outdated and blames it on the user. Newer versions (v1.5.0+) do warn correctly and send the correct message.
Look at which version of the game you're playing, which you can see in the top left corner of the main menu, then download an Impostor version for that game. Every [release on the release page](https://github.com/Impostor/Impostor/releases) shows which version of the game it is compatible with. If your game version is newer than the latest release, check if the [latest build from CI works](https://nightly.link/Impostor/Impostor/workflows/ci/master).
## Disconnected with `You disconnected from the server. Reliable Packet 1 ...`
Please double-check that you have followed the [Server Configuration](Server-configuration.md) correctly.
**NOTE: Your public ip does not start with `10`, `127` or `192`**
Also check if the port Impostor (ListenPort) is listening on is correctly port-forwarded for UDP (or TCP/UDP).
## `Could not load file or assembly...`
Please check that you only have **working** plugins in the `plugins` folder.
Please check that you only have **working** plugins in the `plugins` folder.
This error can be caused by non-plugin files or plugins that are not working correctly.
## My question is not yet answered and I'm still having problems!
That's unfortunate. Join the [Impostor Discord](https://discord.gg/Mk3w6Tb), ask your question there and we'll try to help you out. Note that we're not always available, so it may take some time to get an answer. To make answering your question easier, please add the following details:
- Which version of Impostor are you using?
- Which version or Among Us are you using?
- Which operating system are you running Impostor on?
- If you have console logs, attaching these will also help.
+9 -12
View File
@@ -19,24 +19,24 @@ Impostor has support for plugins. This document will help you to setup a develop
- [Impostor versions](#impostor-versions)
- [9. Missing/invalid data or want more functions?](#9-missinginvalid-data-or-want-more-functions)
## 1. Install .NET Core SDK
## 1. Install .NET SDK
Download and install the latest .NET Core SDK.
Download and install the latest .NET SDK.
https://dotnet.microsoft.com/download
## 2. Create a C# project
The first step is creating a new C# project, it must be a **Class Library (.NET Standard)**. The target framework can be any of those compatible with .NET 5, which includes:
The first step is creating a new C# project, it must be a **Class Library (.NET Standard)**. The target framework can be any of those compatible with .NET 6, which includes:
- .NET Standard 2.0
- .NET Standard 2.1
- .NET Core 3.1
- .NET 5
- .NET 6
For more information about compatibility, see https://docs.microsoft.com/en-us/dotnet/standard/net-standard.
> At the moment of writing this document, I recommend you to use **.NET Standard 2.1** until .NET 5 is released officially. This should give you enough functionality. If not, upgrade to .NET Core 3.1.
> At the moment of writing this document, I recommend you to use **.NET Standard 2.1**. This should give you enough functionality. If not, upgrade to .NET 6.
When the project has been created, you should have `Class.cs` and `Project.csproj` files. Your `Project.csproj` should look something like this.
@@ -62,16 +62,13 @@ Make sure to get a prerelease if you are writing a plugin for a dev release of t
1. Right click your project.
2. Click `Manage NuGet Packages`.
3. Click `Browse`.
4. Next to the search bar, enable `Include prerelease`.
5. Search for `Impostor.Api`.
6. Click the `Impostor.Api` result and press install on the right side.
4. Search for `Impostor.Api`.
5. Click the `Impostor.Api` result and press install on the right side.
### Dotnet CLI
> Make sure to grab the latest (pre-)release version from NuGet [here](https://www.nuget.org/packages/Impostor.Api).
1. Open your project folder in command prompt / bash.
2. Run `dotnet add package Impostor.Api -v "1.2.0-ci.58"`.
2. Run `dotnet add package Impostor.Api`.
## 4. The plugin class
@@ -340,4 +337,4 @@ Create an issue:
- [Suggest a function](https://github.com/Impostor/Impostor/issues/new?template=3--api-suggestion.md)
- [Data is invalid](https://github.com/Impostor/Impostor/issues/new?template=4--api-invalid.md)
- [Data is unavailable](https://github.com/Impostor/Impostor/issues/new?template=5--api-missing.md)
- [Other](https://github.com/Impostor/Impostor/issues/new?template=6--api-other.md)
- [Other](https://github.com/Impostor/Impostor/issues/new?template=6--api-other.md)
+7 -1
View File
@@ -144,6 +144,12 @@ dotnet_naming_style.end_in_async.word_separator =
# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}'
dotnet_diagnostic.RS2008.severity = none
# IDE0005: Remove unnecessary import
dotnet_diagnostic.IDE0005.severity = warning
# IDE0007: Use `var` instead of explicit type
dotnet_diagnostic.IDE0007.severity = warning
# IDE0035: Remove unreachable code
dotnet_diagnostic.IDE0035.severity = warning
@@ -171,7 +177,7 @@ csharp_new_line_between_query_expression_clauses = true
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_case_contents_when_block = false
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
+4 -1
View File
@@ -1,7 +1,10 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.3.0</VersionPrefix>
<TargetFramework>net6.0</TargetFramework>
<VersionPrefix>1.7.2</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>
<EnforceCodeStyleInBuild Condition="$(MSBuildProjectName)!='Hazel'">true</EnforceCodeStyleInBuild>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,4 +1,4 @@
using Impostor.Server.Net.Inner;
using Impostor.Api.Net.Inner;
namespace Impostor.Api
{
@@ -1,4 +1,4 @@
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
public class AntiCheatConfig
{
@@ -0,0 +1,11 @@
namespace Impostor.Api.Config
{
public class CompatibilityConfig
{
public const string Section = "Compatibility";
public bool AllowFutureGameVersions { get; set; } = false;
public bool AllowVersionMixing { get; set; } = false;
}
}
@@ -1,4 +1,4 @@
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
public class DebugConfig
{
@@ -1,10 +1,15 @@
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
public static class DisconnectMessages
{
public const string Error = "There was an internal server error. " +
"Check the server console for more information. " +
"Please report the issue on the AmongUsServer GitHub if it keeps happening.";
"Please report the issue on the Impostor GitHub if it keeps happening.";
public const string ClientOutdated = "Please update your game to play in this lobby.";
public const string ClientTooNew = "Your game version is too new for this lobby. " +
"If you want to join this lobby you need to downgrade your client.";
public const string Destroyed = "The game you tried to join is being destroyed. " +
"Please create a new game.";
@@ -15,5 +20,11 @@
public const string UsernameLength = "Your username is too long, please make it shorter.";
public const string UsernameIllegalCharacters = "Your username contains illegal characters, please remove them.";
public const string VersionClientTooOld = "Please update your game to play on this server.";
public const string VersionServerTooOld = "Your client is too new, please update your Impostor server to play.";
public const string VersionUnsupported = "Your client version is unsupported, please update your Game and/or Impostor server.";
}
}
@@ -1,8 +1,8 @@
using Impostor.Server.Utils;
using Impostor.Api.Utils;
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
internal class ServerConfig
public class ServerConfig
{
public const string Section = "Server";
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
public class ServerRedirectorConfig
{
@@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Server.Config
namespace Impostor.Api.Config
{
public class ServerRedirectorNode
{
@@ -1,43 +0,0 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Announcements
{
/// <summary>
/// Event fired after client requests a announcement.
/// </summary>
public interface IAnnouncementRequestEvent : IEvent
{
public interface IResponse
{
/// <summary>
/// Gets or sets FreeWeekendState, currently unused by the client.
/// </summary>
public FreeWeekendState FreeWeekendState { get; set; }
/// <summary>
/// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes.
/// </summary>
public bool UseCached { get; set; }
/// <summary>
/// Gets or sets announcement, should be null when <see cref="UseCached" /> is set to true.
/// </summary>
public Announcement? Announcement { get; set; }
}
/// <summary>
/// Gets client's last announcement id.
/// </summary>
public int Id { get; }
/// <summary>
/// Gets client's language.
/// </summary>
public Language Language { get; }
/// <summary>
/// Gets or sets plugin made response.
/// </summary>
public IResponse Response { get; set; }
}
}
@@ -0,0 +1,12 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events.Client
{
/// <summary>
/// Called just after a <see cref="IClient"/> is created and connected.
/// </summary>
public interface IClientConnectedEvent : IClientEvent
{
IClient Client { get; }
}
}
@@ -0,0 +1,13 @@
using Impostor.Api.Net;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Events.Client
{
/// <summary>
/// Called just before a <see cref="IHazelConnection"/> is registered.
/// </summary>
public interface IClientConnectionEvent : IClientEvent
{
IMessageReader HandshakeData { get; }
}
}
@@ -0,0 +1,9 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events.Client
{
public interface IClientEvent : IEvent
{
IHazelConnection Connection { get; }
}
}
@@ -0,0 +1,25 @@
using Impostor.Api.Games;
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
/// <summary>
/// Called just before a new <see cref="IGame"/> is created.
/// </summary>
public interface IGameCreationEvent : IEventCancelable
{
/// <summary>
/// Gets the client that requested creation of the game.
/// </summary>
/// <remarks>
/// Will be null if game creation was requested by a plugin.
/// </remarks>
IClient? Client { get; }
/// <summary>
/// Gets or sets the desired <see cref="Games.GameCode"/>.
/// </summary>
/// <exception cref="ImpostorException">If the GameCode is invalid or already used in another game.</exception>
GameCode? GameCode { get; set; }
}
}
@@ -0,0 +1,11 @@
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGameHostChangedEvent : IGameEvent
{
IClientPlayer PreviousHost { get; }
IClientPlayer? NewHost { get; }
}
}
@@ -1,6 +1,9 @@
namespace Impostor.Api.Events
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGamePlayerJoinedEvent : IGameEvent
{
IClientPlayer Player { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Games;
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
/// <summary>
/// Called just before a <see cref="IClientPlayer"/> joins a game.
/// </summary>
public interface IGamePlayerJoiningEvent : IGameEvent
{
IClientPlayer Player { get; }
GameJoinResult? JoinResult { get; set; }
}
}
@@ -1,6 +1,11 @@
namespace Impostor.Api.Events
using Impostor.Api.Net;
namespace Impostor.Api.Events
{
public interface IGamePlayerLeftEvent : IGameEvent
{
IClientPlayer Player { get; }
bool IsBan { get; }
}
}
@@ -1,6 +1,17 @@
namespace Impostor.Api.Events.Meeting
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Meeting
{
public interface IMeetingEndedEvent : IMeetingEvent
{
/// <summary>
/// Gets the exiled player.
/// </summary>
IInnerPlayerControl? Exiled { get; }
/// <summary>
/// Gets a value indicating whether meeting result is a tie.
/// </summary>
bool IsTie { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player enters a vent.
/// </summary>
public interface IPlayerEnterVentEvent : IPlayerEvent
{
/// <summary>
/// Gets the entered vent.
/// </summary>
public IVent Vent { get; }
}
}
@@ -0,0 +1,15 @@
using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player exits a vent.
/// </summary>
public interface IPlayerExitVentEvent : IPlayerEvent
{
/// <summary>
/// Gets the exited vent.
/// </summary>
public IVent Vent { get; }
}
}
@@ -2,16 +2,14 @@ using Impostor.Api.Innersloth;
namespace Impostor.Api.Events.Player
{
/// <summary>
/// Called whenever a player moves to another vent.
/// </summary>
public interface IPlayerVentEvent : IPlayerEvent
{
/// <summary>
/// Gets get the id of the used vent.
/// Gets the vent player moved to.
/// </summary>
public VentLocation VentId { get; }
/// <summary>
/// Gets a value indicating whether the vent was entered or exited.
/// </summary>
public bool VentEnter { get; }
public IVent NewVent { get; }
}
}
@@ -0,0 +1,26 @@
using Impostor.Api.Net.Inner.Objects;
namespace Impostor.Api.Events.Player
{
public enum VoteType : byte
{
HasNotVoted = 255,
Missed = 254,
Skipped = 253,
Dead = 252,
Player = 0,
}
public interface IPlayerVotedEvent : IPlayerEvent
{
/// <summary>
/// Gets the player he voted for.
/// </summary>
IInnerPlayerControl? VotedFor { get; }
/// <summary>
/// Gets the Vote type.
/// </summary>
VoteType VoteType { get; }
}
}
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Impostor.Server.Events
namespace Impostor.Api.Events
{
/// <summary>
/// Disposes multiple <see cref="IDisposable" />.
/// </summary>
internal class MultiDisposable : IDisposable
public class MultiDisposable : IDisposable
{
private readonly IEnumerable<IDisposable> _disposables;
@@ -15,6 +16,10 @@ namespace Impostor.Server.Events
_disposables = disposables;
}
public MultiDisposable(params IDisposable[] disposables) : this(disposables.AsEnumerable())
{
}
public void Dispose()
{
foreach (var disposable in _disposables)
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Impostor.Api
{
public static class DictionaryExtensions
{
/// <summary>Returns a read-only <see cref="ReadOnlyDictionary{TKey,TValue}" /> wrapper for the dictionary.</summary>
/// <param name="dictionary">An <see cref="IDictionary{TKey,TValue}" /> to create a <see cref="ReadOnlyDictionary{TKey,TValue}" /> from.</param>
/// <typeparam name="TKey">The type of the keys of <paramref name="dictionary" />.</typeparam>
/// <typeparam name="TValue">The type of the values of <paramref name="dictionary" />.</typeparam>
/// <returns>An object that acts as a read-only wrapper around the <see cref="IDictionary{TKey,TValue}" />.</returns>
public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
where TKey : notnull
{
return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
}
}
@@ -16,6 +16,13 @@ namespace Impostor.Api
return original[0];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static short ReadInt16(this ref ReadOnlySpan<byte> input)
{
var original = Advance<short>(ref input);
return BinaryPrimitives.ReadInt16LittleEndian(original);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReadInt32(this ref ReadOnlySpan<byte> input)
{
@@ -35,9 +42,7 @@ namespace Impostor.Api
{
var original = Advance<float>(ref input);
// BitConverter.Int32BitsToSingle
// Doesn't exist in net 2.0 for some reason
return Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original));
return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(original));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -46,12 +51,6 @@ namespace Impostor.Api
return input.ReadByte() != 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe float Int32BitsToSingle(int value)
{
return *((float*)&value);
}
/// <summary>
/// Advances the position of <paramref name="input" /> by the size of <typeparamref name="T" />.
/// </summary>
+4 -2
View File
@@ -1,4 +1,4 @@
using System;
using System;
using Impostor.Api.Innersloth;
namespace Impostor.Api.Games
@@ -14,13 +14,15 @@ namespace Impostor.Api.Games
public GameCode(string code)
{
Value = GameCodeParser.GameNameToInt(code);
Code = code;
Code = code.ToUpperInvariant();
}
public string Code { get; }
public int Value { get; }
public bool IsInvalid => Value == -1;
public static implicit operator string(GameCode code) => code.Code;
public static implicit operator int(GameCode code) => code.Value;
+10
View File
@@ -37,6 +37,16 @@
/// </summary>
GameDestroyed,
/// <summary>
/// The host has a newer version of the game and the client should update.
/// </summary>
ClientOutdated,
/// <summary>
/// The host has an older version of the game and the client should downgrade.
/// </summary>
ClientTooNew,
/// <summary>
/// Custom error by a plugin.
/// </summary>
+19
View File
@@ -90,5 +90,24 @@ namespace Impostor.Api.Games
/// <param name="id">ID of the client.</param>
/// <returns>A <see cref="ValueTask" /> representing the asynchronous operation.</returns>
ValueTask SendToAsync(IMessageWriter writer, int id);
/// <summary>
/// Creates a MessageWriter with GameData header.
/// </summary>
/// <remarks>Use with caution, recommended only for advanced developers.</remarks>
/// <param name="targetNetId">Net id of the InnerNetObject.</param>
/// <param name="callId">Rpc id of the message.</param>
/// <param name="targetClientId">Client id of GameDataTo's target.</param>
/// <param name="type">Message type of the message.</param>
/// <returns>A <see cref="IMessageWriter" /> that you can fill with rpc data and send using <see cref="FinishRpcAsync"/>.</returns>
IMessageWriter StartRpc(uint targetNetId, RpcCalls callId, int? targetClientId, MessageType type = MessageType.Reliable);
/// <summary>
/// Finishes rpc message and sends it to the target.
/// </summary>
/// <param name="writer">Message writer of the rpc.</param>
/// <param name="targetClientId">Id of the receiving client.</param>
/// <returns>A <see cref="ValueTask" /> representing the asynchronous operation.</returns>
ValueTask FinishRpcAsync(IMessageWriter writer, int? targetClientId = null);
}
}
@@ -10,6 +10,12 @@ namespace Impostor.Api.Games.Managers
IGame? Find(GameCode code);
ValueTask<IGame> CreateAsync(GameOptionsData options);
/// <summary>
/// Creates a new game.
/// </summary>
/// <param name="options">Game options.</param>
/// <returns>Created game or null if creation was cancelled by a plugin.</returns>
/// <exception cref="ImpostorException">Thrown when game creation failed.</exception>
ValueTask<IGame?> CreateAsync(GameOptionsData options);
}
}
+2 -2
View File
@@ -27,8 +27,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Nullable" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -1,14 +0,0 @@
namespace Impostor.Api.Innersloth
{
public readonly struct Announcement
{
public readonly int Id;
public readonly string Message;
public Announcement(int id, string message)
{
Id = id;
Message = message;
}
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum ColorType : byte
public enum ColorType
{
Red = 0,
Blue = 1,
@@ -14,5 +14,11 @@
Brown = 9,
Cyan = 10,
Lime = 11,
Maroon = 12,
Rose = 13,
Banana = 14,
Gray = 15,
Tan = 16,
Coral = 17,
}
}
@@ -1,101 +0,0 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum HatType : uint
{
NoHat = 0,
Astronaut = 1,
BaseballCap = 2,
BrainSlug = 3,
BushHat = 4,
CaptainsHat = 5,
DoubleTopHat = 6,
Flowerpot = 7,
Goggles = 8,
HardHat = 9,
Military = 10,
PaperHat = 11,
PartyHat = 12,
Police = 13,
Stethescope = 14,
TopHat = 15,
TowelWizard = 16,
Ushanka = 17,
Viking = 18,
WallCap = 19,
Snowman = 20,
Reindeer = 21,
Lights = 22,
Santa = 23,
Tree = 24,
Present = 25,
Candycanes = 26,
ElfHat = 27,
NewYears2018 = 28,
WhiteHat = 29,
Crown = 30,
Eyebrows = 31,
HaloHat = 32,
HeroCap = 33,
PipCap = 34,
PlungerHat = 35,
ScubaHat = 36,
StickminHat = 37,
StrawHat = 38,
TenGallonHat = 39,
ThirdEyeHat = 40,
ToiletPaperHat = 41,
Toppat = 42,
BlackFedora = 43,
SkiGoggles = 44,
Headphones = 45,
MaskHat = 46,
PaperMask = 47,
Security = 48,
StrapHat = 49,
Banana = 50,
Beanie = 51,
Bear = 52,
Cheese = 53,
Cherry = 54,
Egg = 55,
GreenFedora = 56,
Flamingo = 57,
FlowerPin = 58,
Helmet = 59,
Plant = 60,
BatEyes = 61,
BatWings = 62,
Horns = 63,
Mohawk = 64,
Pumpkin = 65,
ScaryBag = 66,
Witch = 67,
Wolf = 68,
Pirate = 69,
Plague = 70,
Machete = 71,
Fred = 72,
MinerCap = 73,
WinterHat = 74,
Archae = 75,
Antenna = 76,
Balloon = 77,
BirdNest = 78,
BlackBelt = 79,
Caution = 80,
Chef = 81,
CopHat = 82,
DoRag = 83,
DumSticker = 84,
Fez = 85,
GeneralHat = 86,
GreyThing = 87,
HunterCap = 88,
JungleHat = 89,
MiniCrewmate = 90,
NinjaMask = 91,
RamHorns = 92,
SnowCrewmate = 93,
GeoffHat = 94,
}
}
@@ -1,18 +0,0 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum PetType : uint
{
NoPet = 0,
Alien = 1,
Crewmate = 2,
Doggy = 3,
Stickmin = 4,
Hamster = 5,
Robot = 6,
Ufo = 7,
Ellie = 8,
Squig = 9,
Bedcrab = 10,
Glitch = 11,
}
}
@@ -0,0 +1,56 @@
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth.Customization
{
public class PlayerOutfit
{
public ColorType Color { get; internal set; } = (ColorType)(-1);
public string HatId { get; internal set; } = "missing";
public string PetId { get; internal set; } = "missing";
public string SkinId { get; internal set; } = "missing";
public string VisorId { get; internal set; } = "missing";
public string NamePlateId { get; internal set; } = "missing";
public string PlayerName { get; internal set; } = "missing";
public bool IsIncomplete
{
get
{
if (!string.IsNullOrEmpty(PlayerName) && Color != (ColorType)(-1) && HatId != "missing" && PetId != "missing" && SkinId != "missing" && VisorId != "missing")
{
return NamePlateId == "missing";
}
return true;
}
}
public void Serialize(IMessageWriter writer)
{
writer.Write(PlayerName);
writer.WritePacked((int)Color);
writer.Write(HatId);
writer.Write(PetId);
writer.Write(SkinId);
writer.Write(VisorId);
writer.Write(NamePlateId);
}
public void Deserialize(IMessageReader reader)
{
PlayerName = reader.ReadString();
Color = (ColorType)reader.ReadPackedInt32();
HatId = reader.ReadString();
PetId = reader.ReadString();
SkinId = reader.ReadString();
VisorId = reader.ReadString();
NamePlateId = reader.ReadString();
}
}
}
@@ -0,0 +1,8 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum PlayerOutfitType
{
Default,
Shapeshifted,
}
}
@@ -1,22 +0,0 @@
namespace Impostor.Api.Innersloth.Customization
{
public enum SkinType : uint
{
None = 0,
Astro = 1,
Capt = 2,
Mech = 3,
Military = 4,
Police = 5,
Science = 6,
SuitB = 7,
SuitW = 8,
Wall = 9,
Hazmat = 10,
Security = 11,
Tarmac = 12,
Miner = 13,
Winter = 14,
Archae = 15,
}
}
@@ -1,12 +0,0 @@
using System;
namespace Impostor.Api.Innersloth
{
[Flags]
public enum FreeWeekendState : byte
{
NotFree,
FreeMIRA,
FreePolus,
}
}
+12 -5
View File
@@ -6,14 +6,21 @@ namespace Impostor.Api.Innersloth
public enum GameKeywords : uint
{
All = 0,
Other = 1,
Spanish = 2,
English = 256,
SpanishLA = 2,
Brazilian = 2048,
Portuguese = 16,
Korean = 4,
Russian = 8,
Portuguese = 16,
Dutch = 4096,
Filipino = 64,
French = 8192,
German = 16384,
Italian = 32768,
Japanese = 512,
SpanishEU = 1024,
Arabic = 32,
Filipone = 64,
Polish = 128,
English = 256,
Other = 1,
}
}
+34 -9
View File
@@ -9,7 +9,7 @@ namespace Impostor.Api.Innersloth
/// <summary>
/// The latest major version of the game client.
/// </summary>
public const int LatestVersion = 4;
public const int LatestVersion = 5;
/// <summary>
/// Gets or sets host's version of the game.
@@ -124,6 +124,11 @@ namespace Impostor.Api.Innersloth
/// </summary>
public TaskBarUpdate TaskBarUpdate { get; set; } = TaskBarUpdate.Always;
/// <summary>
/// Gets or sets role options.
/// </summary>
public RoleOptionsData RoleOptions { get; set; } = new RoleOptionsData();
/// <summary>
/// Gets or sets a value indicating whether the GameOptions are the default ones.
/// </summary>
@@ -166,24 +171,34 @@ namespace Impostor.Api.Innersloth
writer.Write((uint)VotingTime);
writer.Write((bool)IsDefaults);
if (version > 1)
if (version >= 2)
{
writer.Write((byte)EmergencyCooldown);
}
if (version > 2)
if (version >= 3)
{
writer.Write((bool)ConfirmImpostor);
writer.Write((bool)VisualTasks);
}
if (version > 3)
if (version >= 4)
{
writer.Write((bool)AnonymousVotes);
writer.Write((byte)TaskBarUpdate);
}
if (version > 4)
if (version >= 5)
{
RoleOptions.Serialize(writer);
}
if (version >= 6)
{
// Nothing was changed in V6
}
if (version > 6)
{
throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
}
@@ -228,24 +243,34 @@ namespace Impostor.Api.Innersloth
IsDefaults = bytes.ReadBoolean();
if (Version > 1)
if (Version >= 2)
{
EmergencyCooldown = bytes.ReadByte();
}
if (Version > 2)
if (Version >= 3)
{
ConfirmImpostor = bytes.ReadBoolean();
VisualTasks = bytes.ReadBoolean();
}
if (Version > 3)
if (Version >= 4)
{
AnonymousVotes = bytes.ReadBoolean();
TaskBarUpdate = (TaskBarUpdate)bytes.ReadByte();
}
if (Version > 4)
if (Version >= 5)
{
RoleOptions = RoleOptionsData.Deserialize(bytes);
}
if (Version >= 6)
{
// Nothing was changed in V6
}
if (Version > 6)
{
throw new ImpostorException($"Unknown GameOptionsData version {Version}.");
}
+13 -3
View File
@@ -1,10 +1,20 @@
namespace Impostor.Api.Innersloth
{
public class GameVersion
public static class GameVersion
{
public static int GetVersion(int year, int month, int day, int rev = 0)
public static int GetVersion(int year, int month, int day, int revision = 0)
{
return (year * 25000) + (month * 1800) + (day * 50) + rev;
return (year * 25000) + (month * 1800) + (day * 50) + revision;
}
public static void ParseVersion(int version, out int year, out int month, out int day, out int revision)
{
year = version / 25000;
version %= 25000;
month = version / 1800;
version %= 1800;
day = version / 50;
revision = version % 50;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace Impostor.Api.Innersloth
{
public interface ITask
{
int Id { get; }
string Name { get; }
TaskTypes Type { get; }
TaskCategories Category { get; }
bool IsVisual { get; }
}
}
+19
View File
@@ -0,0 +1,19 @@
using System.Numerics;
namespace Impostor.Api.Innersloth
{
public interface IVent
{
int Id { get; }
string Name { get; }
Vector2 Position { get; }
IVent? Left { get; }
IVent? Center { get; }
IVent? Right { get; }
}
}
+9 -1
View File
@@ -3,9 +3,17 @@ namespace Impostor.Api.Innersloth
public enum Language
{
English,
Spanish,
SpanishLA,
Brazilian,
Portuguese,
Korean,
Russian,
Dutch,
Filipino,
French,
German,
Italian,
Japanese,
SpanishEU,
}
}
-45
View File
@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Numerics;
namespace Impostor.Api.Innersloth
{
public class MapSpawn
{
private MapSpawn(float spawnRadius, Vector2 initialSpawnCenter, Vector2 meetingSpawnCenter)
{
SpawnRadius = spawnRadius;
InitialSpawnCenter = initialSpawnCenter;
MeetingSpawnCenter = meetingSpawnCenter;
}
public static Dictionary<MapTypes, MapSpawn> Maps { get; } = new Dictionary<MapTypes, MapSpawn>
{
[MapTypes.Skeld] = new MapSpawn(1.6f, new Vector2(-0.72f, 0.62f), new Vector2(-0.72f, 0.62f)),
[MapTypes.MiraHQ] = new MapSpawn(1.55f, new Vector2(-4.4f, 2.2f), new Vector2(24.043f, 1.72f)),
[MapTypes.Polus] = new MapSpawn(1f, new Vector2(16.64f, -2.46f), new Vector2(17.726f, -16.286f)),
};
public float SpawnRadius { get; }
public Vector2 InitialSpawnCenter { get; }
public Vector2 MeetingSpawnCenter { get; }
public Vector2 GetSpawnLocation(int playerId, int numPlayer, bool initialSpawn)
{
var vector = new Vector2(0, 1);
vector = Rotate(vector, (playerId - 1) * (360f / numPlayer));
vector *= this.SpawnRadius;
return (initialSpawn ? this.InitialSpawnCenter : this.MeetingSpawnCenter) + vector + new Vector2(0f, 0.3636f);
}
private static Vector2 Rotate(Vector2 self, float degrees)
{
var f = 0.017453292f * degrees;
var num = (float)Math.Cos(f);
var num2 = (float)Math.Sin(f);
return new Vector2((self.X * num) - (num2 * self.Y), (self.X * num2) + (num * self.Y));
}
}
}
+1
View File
@@ -5,5 +5,6 @@
Skeld = 0,
MiraHQ = 1,
Polus = 2,
Airship = 4,
}
}
@@ -0,0 +1,94 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class AirshipData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal AirshipData()
{
var vents = new[]
{
new AirshipVent(this, AirshipVent.Ids.Vault, new Vector2(-12.6322f, 8.4735f), left: AirshipVent.Ids.Cockpit),
new AirshipVent(this, AirshipVent.Ids.Cockpit, new Vector2(-22.099f, -1.512f), left: AirshipVent.Ids.Vault, right: AirshipVent.Ids.ViewingDeck),
new AirshipVent(this, AirshipVent.Ids.ViewingDeck, new Vector2(-15.659f, -11.6991f), left: AirshipVent.Ids.Cockpit),
new AirshipVent(this, AirshipVent.Ids.EngineRoom, new Vector2(0.203f, -2.5361f), left: AirshipVent.Ids.Kitchen, right: AirshipVent.Ids.MainHallBottom),
new AirshipVent(this, AirshipVent.Ids.Kitchen, new Vector2(-2.6019f, -9.338f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.MainHallBottom),
new AirshipVent(this, AirshipVent.Ids.MainHallBottom, new Vector2(7.021f, -3.730999f), left: AirshipVent.Ids.EngineRoom, right: AirshipVent.Ids.Kitchen),
new AirshipVent(this, AirshipVent.Ids.GapRight, new Vector2(9.814f, 3.206f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapLeft),
new AirshipVent(this, AirshipVent.Ids.GapLeft, new Vector2(12.663f, 5.922f), left: AirshipVent.Ids.MainHallTop, right: AirshipVent.Ids.GapRight),
new AirshipVent(this, AirshipVent.Ids.MainHallTop, new Vector2(3.605f, 6.923f), left: AirshipVent.Ids.GapLeft, right: AirshipVent.Ids.GapRight),
new AirshipVent(this, AirshipVent.Ids.Showers, new Vector2(23.9869f, -1.386f), left: AirshipVent.Ids.Records, right: AirshipVent.Ids.CargoBay),
new AirshipVent(this, AirshipVent.Ids.Records, new Vector2(23.2799f, 8.259998f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.CargoBay),
new AirshipVent(this, AirshipVent.Ids.CargoBay, new Vector2(30.4409f, -3.577f), left: AirshipVent.Ids.Showers, right: AirshipVent.Ids.Records),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new AirshipTask(AirshipTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new AirshipTask(AirshipTask.Ids.MeetingRoomEnterIDCode, TaskTypes.EnterIdCode, TaskCategories.CommonTask),
new AirshipTask(AirshipTask.Ids.ElectricalCalibrateDistributor, TaskTypes.CalibrateDistributor, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ElectricalResetBreakers, TaskTypes.ResetBreakers, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VaultRoomDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.BrigDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.GapRoomDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.RecordsDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayUnlockSafe, TaskTypes.UnlockSafe, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VentilationStartFans, TaskTypes.StartFans, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MainHallEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MedicalEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.KitchenEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MainHallDevelopPhotos, TaskTypes.DevelopPhotos, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CargoBayFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.SecurityRewindTapes, TaskTypes.RewindTapes, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.LoungeEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ShowersEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.VaultRoomPolishRuby, TaskTypes.PolishRuby, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.CockpitStabilizeSteering, TaskTypes.StabilizeSteering, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CockpitDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.CommsDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.MedicalDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ViewingDeckDownloadData, TaskTypes.UploadData, TaskCategories.LongTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToArmory, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToCockpit, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToGapRoom, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToMainHall, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToMeetingRoom, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToShowers, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ElectricalDivertPowerToEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ShowersPickUpTowels, TaskTypes.PickUpTowels, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.LoungeCleanToilet, TaskTypes.CleanToilet, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.VaultRoomDressMannequin, TaskTypes.DressMannequin, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.RecordsSortRecords, TaskTypes.SortRecords, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryPutAwayPistols, TaskTypes.PutAwayPistols, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ArmoryPutAwayRifles, TaskTypes.PutAwayRifles, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.MainHallDecontaminate, TaskTypes.Decontaminate, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.KitchenMakeBurger, TaskTypes.MakeBurger, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.ShowersFixShower, TaskTypes.FixShower, TaskCategories.ShortTask),
new AirshipTask(AirshipTask.Ids.CleanVent, TaskTypes.VentCleaning, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<AirshipVent.Ids, AirshipVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<AirshipTask.Ids, AirshipTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace Impostor.Api.Innersloth.Maps
{
public interface IMapData
{
public static IReadOnlyDictionary<MapTypes, IMapData> Maps { get; } = new Dictionary<MapTypes, IMapData>
{
[MapTypes.Skeld] = new SkeldData(),
[MapTypes.MiraHQ] = new MiraData(),
[MapTypes.Polus] = new PolusData(),
[MapTypes.Airship] = new AirshipData(),
}.AsReadOnly();
IReadOnlyDictionary<int, IVent> Vents { get; }
IReadOnlyDictionary<int, ITask> Tasks { get; }
}
}
@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class MiraData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal MiraData()
{
var vents = new[]
{
new MiraVent(this, MiraVent.Ids.Balcony, new Vector2(23.77f, -1.94f), left: MiraVent.Ids.Medbay, right: MiraVent.Ids.Cafeteria),
new MiraVent(this, MiraVent.Ids.Cafeteria, new Vector2(23.9f, 7.18f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Balcony),
new MiraVent(this, MiraVent.Ids.Reactor, new Vector2(0.4800001f, 10.697f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Launchpad),
new MiraVent(this, MiraVent.Ids.Laboratory, new Vector2(11.606f, 13.816f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.Decontamination, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Office, new Vector2(13.28f, 20.13f), left: MiraVent.Ids.Laboratory, center: MiraVent.Ids.Admin, right: MiraVent.Ids.Greenhouse),
new MiraVent(this, MiraVent.Ids.Admin, new Vector2(22.39f, 17.23f), left: MiraVent.Ids.Greenhouse, center: MiraVent.Ids.Cafeteria, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Greenhouse, new Vector2(17.85f, 25.23f), left: MiraVent.Ids.Admin, right: MiraVent.Ids.Office),
new MiraVent(this, MiraVent.Ids.Medbay, new Vector2(15.41f, -1.82f), left: MiraVent.Ids.Balcony, right: MiraVent.Ids.LockerRoom),
new MiraVent(this, MiraVent.Ids.Decontamination, new Vector2(6.83f, 3.145f), left: MiraVent.Ids.Reactor, center: MiraVent.Ids.LockerRoom, right: MiraVent.Ids.Laboratory),
new MiraVent(this, MiraVent.Ids.LockerRoom, new Vector2(4.29f, 0.5299997f), left: MiraVent.Ids.Medbay, center: MiraVent.Ids.Launchpad, right: MiraVent.Ids.Decontamination),
new MiraVent(this, MiraVent.Ids.Launchpad, new Vector2(-6.18f, 3.56f), left: MiraVent.Ids.Reactor, right: MiraVent.Ids.LockerRoom),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new MiraTask(MiraTask.Ids.HallwayFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new MiraTask(MiraTask.Ids.AdminEnterIDCode, TaskTypes.EnterIdCode, TaskCategories.CommonTask),
new MiraTask(MiraTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.LongTask, true),
new MiraTask(MiraTask.Ids.BalconyClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToAdmin, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToCafeteria, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToCommunications, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToLaunchpad, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToMedbay, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToOffice, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.StorageWaterPlants, TaskTypes.WaterPlants, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ReactorStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToGreenhouse, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.AdminChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.GreenhouseCleanO2Filter, TaskTypes.Filter, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaunchpadFuelEngines, TaskTypes.FuelEngines, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaboratoryAssembleArtifact, TaskTypes.AssembleArtifact, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaboratorySortSamples, TaskTypes.SortSamples, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.AdminPrimeShields, TaskTypes.PrimeShields, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.CafeteriaEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.BalconyMeasureWeather, TaskTypes.MeasureWeather, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.ElectricalDivertPowerToLaboratory, TaskTypes.DivertPower, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.CafeteriaBuyBeverage, TaskTypes.BuyBeverage, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.OfficeProcessData, TaskTypes.ProcessData, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.LaunchpadRunDiagnostics, TaskTypes.RunDiagnostics, TaskCategories.LongTask),
new MiraTask(MiraTask.Ids.ReactorUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
new MiraTask(MiraTask.Ids.CleanVent, TaskTypes.VentCleaning, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<MiraVent.Ids, MiraVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<MiraTask.Ids, MiraTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class PolusData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal PolusData()
{
var vents = new[]
{
new PolusVent(this, PolusVent.Ids.Security, new Vector2(1.929f, -9.558001f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Electrical),
new PolusVent(this, PolusVent.Ids.Electrical, new Vector2(6.9f, -14.41f), left: PolusVent.Ids.O2, right: PolusVent.Ids.Security),
new PolusVent(this, PolusVent.Ids.O2, new Vector2(3.51f, -16.58f), left: PolusVent.Ids.Electrical, right: PolusVent.Ids.Security),
new PolusVent(this, PolusVent.Ids.Communications, new Vector2(12.304f, -18.898f), left: PolusVent.Ids.Storage, right: PolusVent.Ids.Office),
new PolusVent(this, PolusVent.Ids.Office, new Vector2(16.379f, -19.599f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Storage),
new PolusVent(this, PolusVent.Ids.Admin, new Vector2(20.089f, -25.517f), left: PolusVent.Ids.OutsideAdmin, right: PolusVent.Ids.Lava),
new PolusVent(this, PolusVent.Ids.Laboratory, new Vector2(32.963f, -9.526f), right: PolusVent.Ids.Lava),
new PolusVent(this, PolusVent.Ids.Lava, new Vector2(30.907f, -11.86f), left: PolusVent.Ids.Laboratory, right: PolusVent.Ids.Admin),
new PolusVent(this, PolusVent.Ids.Storage, new Vector2(22f, -12.19f), left: PolusVent.Ids.Communications, right: PolusVent.Ids.Office),
new PolusVent(this, PolusVent.Ids.RightStabilizer, new Vector2(24.02f, -8.39f), left: PolusVent.Ids.LeftStabilizer),
new PolusVent(this, PolusVent.Ids.LeftStabilizer, new Vector2(9.64f, -7.72f), left: PolusVent.Ids.RightStabilizer),
new PolusVent(this, PolusVent.Ids.OutsideAdmin, new Vector2(18.93f, -24.85f), right: PolusVent.Ids.Admin),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new PolusTask(PolusTask.Ids.OfficeSwipeCard, TaskTypes.SwipeCard, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.DropshipInsertKeys, TaskTypes.InsertKeys, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.OfficeScanBoardingPass, TaskTypes.ScanBoardingPass, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new PolusTask(PolusTask.Ids.WeaponsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.OfficeDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.ElectricalDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2DownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.StorageFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.BoilerRoomOpenWaterways, TaskTypes.OpenWaterways, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.MedbayInspectSample, TaskTypes.InspectSample, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.BoilerRoomReplaceWaterJug, TaskTypes.ReplaceWaterJug, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_GI, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_IRO, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_PD, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_TB, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.CommunicationsRebootWiFi, TaskTypes.RebootWifi, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.O2MonitorTree, TaskTypes.MonitorOxygen, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.SpecimenRoomStoreArtifacts, TaskTypes.StoreArtifact, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2FillCanisters, TaskTypes.FillCanisters, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.O2EmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.DropshipChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.ShortTask, true),
new PolusTask(PolusTask.Ids.WeaponsClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.ShortTask, true),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_CA, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.OutsideFixWeatherNodeNode_MLG, TaskTypes.ActivateWeatherNodes, TaskCategories.LongTask),
new PolusTask(PolusTask.Ids.LaboratoryAlignTelescope, TaskTypes.AlignTelescope, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.LaboratoryRepairDrill, TaskTypes.RepairDrill, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.LaboratoryRecordTemperature, TaskTypes.RecordTemperature, TaskCategories.ShortTask),
new PolusTask(PolusTask.Ids.OutsideRecordTemperature, TaskTypes.RecordTemperature, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<PolusVent.Ids, PolusVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<PolusTask.Ids, PolusTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Impostor.Api.Innersloth.Maps.Tasks;
using Impostor.Api.Innersloth.Maps.Vents;
namespace Impostor.Api.Innersloth.Maps
{
public class SkeldData : IMapData
{
private readonly IReadOnlyDictionary<int, IVent> _vents;
private readonly IReadOnlyDictionary<int, ITask> _tasks;
internal SkeldData()
{
var vents = new[]
{
new SkeldVent(this, SkeldVent.Ids.Admin, new Vector2(2.544f, -9.955201f), left: SkeldVent.Ids.Cafeteria, right: SkeldVent.Ids.RightHallway),
new SkeldVent(this, SkeldVent.Ids.RightHallway, new Vector2(9.384f, -6.438f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.Cafeteria),
new SkeldVent(this, SkeldVent.Ids.Cafeteria, new Vector2(4.2588f, -0.276f), left: SkeldVent.Ids.Admin, right: SkeldVent.Ids.RightHallway),
new SkeldVent(this, SkeldVent.Ids.Electrical, new Vector2(-9.7764f, -8.034f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Medbay),
new SkeldVent(this, SkeldVent.Ids.UpperEngine, new Vector2(-15.288f, 2.52f), left: SkeldVent.Ids.UpperReactor),
new SkeldVent(this, SkeldVent.Ids.Security, new Vector2(-12.534f, -6.9492f), left: SkeldVent.Ids.Medbay, right: SkeldVent.Ids.Electrical),
new SkeldVent(this, SkeldVent.Ids.Medbay, new Vector2(-10.608f, -4.176f), left: SkeldVent.Ids.Security, right: SkeldVent.Ids.Electrical),
new SkeldVent(this, SkeldVent.Ids.Weapons, new Vector2(8.820001f, 3.324f), right: SkeldVent.Ids.UpperNavigation),
new SkeldVent(this, SkeldVent.Ids.LowerReactor, new Vector2(-20.796f, -6.9528f), left: SkeldVent.Ids.LowerEngine),
new SkeldVent(this, SkeldVent.Ids.LowerEngine, new Vector2(-15.2508f, -13.656f), left: SkeldVent.Ids.LowerReactor),
new SkeldVent(this, SkeldVent.Ids.Shields, new Vector2(9.5232f, -14.3376f), left: SkeldVent.Ids.LowerNavigation),
new SkeldVent(this, SkeldVent.Ids.UpperReactor, new Vector2(-21.876f, -3.0516f), left: SkeldVent.Ids.UpperEngine),
new SkeldVent(this, SkeldVent.Ids.UpperNavigation, new Vector2(16.008f, -3.168f), right: SkeldVent.Ids.Weapons),
new SkeldVent(this, SkeldVent.Ids.LowerNavigation, new Vector2(16.008f, -6.384f), right: SkeldVent.Ids.Shields),
};
Vents = vents.ToDictionary(x => x.Id, x => x).AsReadOnly();
_vents = vents.ToDictionary(x => (int)x.Id, x => (IVent)x).AsReadOnly();
var tasks = new[]
{
new SkeldTask(SkeldTask.Ids.AdminSwipeCard, TaskTypes.SwipeCard, TaskCategories.CommonTask),
new SkeldTask(SkeldTask.Ids.ElectricalFixWiring, TaskTypes.FixWiring, TaskCategories.CommonTask),
new SkeldTask(SkeldTask.Ids.WeaponsClearAsteroids, TaskTypes.ClearAsteroids, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.EnginesAlignEngineOutput, TaskTypes.AlignEngineOutput, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.MedbaySubmitScan, TaskTypes.SubmitScan, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.MedbayInspectSample, TaskTypes.InspectSample, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.StorageFuelEngines, TaskTypes.FuelEngines, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.ReactorStartReactor, TaskTypes.StartReactor, TaskCategories.LongTask),
new SkeldTask(SkeldTask.Ids.O2EmptyChute, TaskTypes.EmptyChute, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.CafeteriaEmptyGarbage, TaskTypes.EmptyGarbage, TaskCategories.LongTask, true),
new SkeldTask(SkeldTask.Ids.CommunicationsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalCalibrateDistributor, TaskTypes.CalibrateDistributor, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationChartCourse, TaskTypes.ChartCourse, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.O2CleanO2Filter, TaskTypes.Filter, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ReactorUnlockManifolds, TaskTypes.UnlockManifolds, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationStabilizeSteering, TaskTypes.StabilizeSteering, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.WeaponsDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ShieldsPrimeShields, TaskTypes.PrimeShields, TaskCategories.ShortTask, true),
new SkeldTask(SkeldTask.Ids.CafeteriaDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.NavigationDownloadData, TaskTypes.UploadData, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToShields, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToWeapons, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToCommunications, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToUpperEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToO2, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToNavigation, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToLowerEngine, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.ElectricalDivertPowerToSecurity, TaskTypes.DivertPower, TaskCategories.ShortTask),
new SkeldTask(SkeldTask.Ids.CleanVent, TaskTypes.VentCleaning, TaskCategories.ShortTask),
};
Tasks = tasks.ToDictionary(x => x.Id, x => x).AsReadOnly();
_tasks = tasks.ToDictionary(x => (int)x.Id, x => (ITask)x).AsReadOnly();
}
public IReadOnlyDictionary<SkeldVent.Ids, SkeldVent> Vents { get; }
IReadOnlyDictionary<int, IVent> IMapData.Vents => _vents;
public IReadOnlyDictionary<SkeldTask.Ids, SkeldTask> Tasks { get; }
IReadOnlyDictionary<int, ITask> IMapData.Tasks => _tasks;
}
}
@@ -0,0 +1,73 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class AirshipTask : ITask
{
internal AirshipTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
ElectricalFixWiring = 0,
MeetingRoomEnterIDCode = 1,
ElectricalCalibrateDistributor = 2,
ElectricalResetBreakers = 3,
VaultRoomDownloadData = 4,
BrigDownloadData = 5,
CargoBayDownloadData = 6,
GapRoomDownloadData = 7,
RecordsDownloadData = 8,
CargoBayUnlockSafe = 9,
VentilationStartFans = 10,
MainHallEmptyGarbage = 11,
MedicalEmptyGarbage = 12,
KitchenEmptyGarbage = 13,
MainHallDevelopPhotos = 14,
CargoBayFuelEngines = 15,
SecurityRewindTapes = 16,
LoungeEmptyGarbage = 17,
ShowersEmptyGarbage = 18,
VaultRoomPolishRuby = 19,
CockpitStabilizeSteering = 20,
ArmoryDownloadData = 21,
CockpitDownloadData = 22,
CommsDownloadData = 23,
MedicalDownloadData = 24,
ViewingDeckDownloadData = 25,
ElectricalDivertPowerToArmory = 26,
ElectricalDivertPowerToCockpit = 27,
ElectricalDivertPowerToGapRoom = 28,
ElectricalDivertPowerToMainHall = 29,
ElectricalDivertPowerToMeetingRoom = 30,
ElectricalDivertPowerToShowers = 31,
ElectricalDivertPowerToEngine = 32,
ShowersPickUpTowels = 33,
LoungeCleanToilet = 34,
VaultRoomDressMannequin = 35,
RecordsSortRecords = 36,
ArmoryPutAwayPistols = 37,
ArmoryPutAwayRifles = 38,
MainHallDecontaminate = 39,
KitchenMakeBurger = 40,
ShowersFixShower = 41,
CleanVent = 42,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,57 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class MiraTask : ITask
{
internal MiraTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
HallwayFixWiring = 0,
AdminEnterIDCode = 1,
MedbaySubmitScan = 2,
BalconyClearAsteroids = 3,
ElectricalDivertPowerToAdmin = 4,
ElectricalDivertPowerToCafeteria = 5,
ElectricalDivertPowerToCommunications = 6,
ElectricalDivertPowerToLaunchpad = 7,
ElectricalDivertPowerToMedbay = 8,
ElectricalDivertPowerToOffice = 9,
StorageWaterPlants = 10,
ReactorStartReactor = 11,
ElectricalDivertPowerToGreenhouse = 12,
AdminChartCourse = 13,
GreenhouseCleanO2Filter = 14,
LaunchpadFuelEngines = 15,
LaboratoryAssembleArtifact = 16,
LaboratorySortSamples = 17,
AdminPrimeShields = 18,
CafeteriaEmptyGarbage = 19,
BalconyMeasureWeather = 20,
ElectricalDivertPowerToLaboratory = 21,
CafeteriaBuyBeverage = 22,
OfficeProcessData = 23,
LaunchpadRunDiagnostics = 24,
ReactorUnlockManifolds = 25,
CleanVent = 26,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,63 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class PolusTask : ITask
{
internal PolusTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
OfficeSwipeCard = 0,
DropshipInsertKeys = 1,
OfficeScanBoardingPass = 2,
ElectricalFixWiring = 3,
WeaponsDownloadData = 4,
OfficeDownloadData = 5,
ElectricalDownloadData = 6,
SpecimenRoomDownloadData = 7,
O2DownloadData = 8,
SpecimenRoomStartReactor = 9,
StorageFuelEngines = 10,
BoilerRoomOpenWaterways = 11,
MedbayInspectSample = 12,
BoilerRoomReplaceWaterJug = 13,
OutsideFixWeatherNodeNode_GI = 14,
OutsideFixWeatherNodeNode_IRO = 15,
OutsideFixWeatherNodeNode_PD = 16,
OutsideFixWeatherNodeNode_TB = 17,
CommunicationsRebootWiFi = 18,
O2MonitorTree = 19,
SpecimenRoomUnlockManifolds = 20,
SpecimenRoomStoreArtifacts = 21,
O2FillCanisters = 22,
O2EmptyGarbage = 23,
DropshipChartCourse = 24,
MedbaySubmitScan = 25,
WeaponsClearAsteroids = 26,
OutsideFixWeatherNodeNode_CA = 27,
OutsideFixWeatherNodeNode_MLG = 28,
LaboratoryAlignTelescope = 29,
LaboratoryRepairDrill = 30,
LaboratoryRecordTemperature = 31,
OutsideRecordTemperature = 32,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,60 @@
namespace Impostor.Api.Innersloth.Maps.Tasks
{
public class SkeldTask : ITask
{
internal SkeldTask(Ids id, TaskTypes type, TaskCategories category, bool isVisual = false)
{
Id = id;
Name = id.ToString();
Type = type;
Category = category;
IsVisual = isVisual;
}
public enum Ids
{
AdminSwipeCard = 0,
ElectricalFixWiring = 1,
WeaponsClearAsteroids = 2,
EnginesAlignEngineOutput = 3,
MedbaySubmitScan = 4,
MedbayInspectSample = 5,
StorageFuelEngines = 6,
ReactorStartReactor = 7,
O2EmptyChute = 8,
CafeteriaEmptyGarbage = 9,
CommunicationsDownloadData = 10,
ElectricalCalibrateDistributor = 11,
NavigationChartCourse = 12,
O2CleanO2Filter = 13,
ReactorUnlockManifolds = 14,
ElectricalDownloadData = 15,
NavigationStabilizeSteering = 16,
WeaponsDownloadData = 17,
ShieldsPrimeShields = 18,
CafeteriaDownloadData = 19,
NavigationDownloadData = 20,
ElectricalDivertPowerToShields = 21,
ElectricalDivertPowerToWeapons = 22,
ElectricalDivertPowerToCommunications = 23,
ElectricalDivertPowerToUpperEngine = 24,
ElectricalDivertPowerToO2 = 25,
ElectricalDivertPowerToNavigation = 26,
ElectricalDivertPowerToLowerEngine = 27,
ElectricalDivertPowerToSecurity = 28,
CleanVent = 29,
}
public Ids Id { get; }
int ITask.Id => (int)Id;
public string Name { get; }
public TaskTypes Type { get; }
public TaskCategories Category { get; }
public bool IsVisual { get; }
}
}
@@ -0,0 +1,61 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class AirshipVent : IVent
{
private readonly Lazy<AirshipVent>? _left;
private readonly Lazy<AirshipVent>? _center;
private readonly Lazy<AirshipVent>? _right;
internal AirshipVent(AirshipData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<AirshipVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<AirshipVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<AirshipVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Vault = 0,
Cockpit = 1,
ViewingDeck = 2,
EngineRoom = 3,
Kitchen = 4,
MainHallBottom = 5,
GapRight = 6,
GapLeft = 7,
MainHallTop = 8,
Showers = 9,
Records = 10,
CargoBay = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public AirshipVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public AirshipVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public AirshipVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,60 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class MiraVent : IVent
{
private readonly Lazy<MiraVent>? _left;
private readonly Lazy<MiraVent>? _center;
private readonly Lazy<MiraVent>? _right;
internal MiraVent(MiraData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<MiraVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<MiraVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<MiraVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Balcony = 1,
Cafeteria = 2,
Reactor = 3,
Laboratory = 4,
Office = 5,
Admin = 6,
Greenhouse = 7,
Medbay = 8,
Decontamination = 9,
LockerRoom = 10,
Launchpad = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public MiraVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public MiraVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public MiraVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,61 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class PolusVent : IVent
{
private readonly Lazy<PolusVent>? _left;
private readonly Lazy<PolusVent>? _center;
private readonly Lazy<PolusVent>? _right;
internal PolusVent(PolusData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<PolusVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<PolusVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<PolusVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Security = 0,
Electrical = 1,
O2 = 2,
Communications = 3,
Office = 4,
Admin = 5,
Laboratory = 6,
Lava = 7,
Storage = 8,
RightStabilizer = 9,
LeftStabilizer = 10,
OutsideAdmin = 11,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public PolusVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public PolusVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public PolusVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,63 @@
using System;
using System.Numerics;
namespace Impostor.Api.Innersloth.Maps.Vents
{
public class SkeldVent : IVent
{
private readonly Lazy<SkeldVent>? _left;
private readonly Lazy<SkeldVent>? _center;
private readonly Lazy<SkeldVent>? _right;
internal SkeldVent(SkeldData data, Ids id, Vector2 position, Ids? left = null, Ids? center = null, Ids? right = null)
{
Id = id;
Name = id.ToString();
Position = position;
_left = left == null ? null : new Lazy<SkeldVent>(() => data.Vents[left.Value]);
_center = center == null ? null : new Lazy<SkeldVent>(() => data.Vents[center.Value]);
_right = right == null ? null : new Lazy<SkeldVent>(() => data.Vents[right.Value]);
}
public enum Ids
{
Admin = 0,
RightHallway = 1,
Cafeteria = 2,
Electrical = 3,
UpperEngine = 4,
Security = 5,
Medbay = 6,
Weapons = 7,
LowerReactor = 8,
LowerEngine = 9,
Shields = 10,
UpperReactor = 11,
UpperNavigation = 12,
LowerNavigation = 13,
}
public Ids Id { get; }
int IVent.Id => (int)Id;
public string Name { get; }
public Vector2 Position { get; }
public SkeldVent? Left => _left?.Value;
IVent? IVent.Left => Left;
public SkeldVent? Center => _center?.Value;
IVent? IVent.Center => Center;
public SkeldVent? Right => _right?.Value;
IVent? IVent.Right => Right;
}
}
@@ -0,0 +1,50 @@
using System;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
{
public class PlatformSpecificData
{
public PlatformSpecificData(Platforms platform, string platformName, ulong? xboxPlatformId = null, ulong? psnPlatformId = null)
{
Platform = platform;
PlatformName = platformName;
XboxPlatformId = xboxPlatformId;
PsnPlatformId = psnPlatformId;
}
public PlatformSpecificData(IMessageReader reader)
{
Platform = (Platforms)reader.Tag;
PlatformName = reader.ReadString();
XboxPlatformId = Platform == Platforms.Xbox ? reader.ReadUInt64() : null;
PsnPlatformId = Platform == Platforms.Playstation ? reader.ReadUInt64() : null;
}
public Platforms Platform { get; }
public string PlatformName { get; }
public ulong? XboxPlatformId { get; }
public ulong? PsnPlatformId { get; }
public void Serialize(IMessageWriter writer)
{
writer.StartMessage((byte)Platform);
writer.Write(PlatformName);
switch (Platform)
{
case Platforms.Xbox:
writer.Write(XboxPlatformId ?? throw new NullReferenceException($"{nameof(XboxPlatformId)} shouldn't be null when {nameof(Platform)} is Xbox"));
break;
case Platforms.Playstation:
writer.Write(PsnPlatformId ?? throw new NullReferenceException($"{nameof(PsnPlatformId)} shouldn't be null when {nameof(Platform)} is Playstation"));
break;
}
writer.EndMessage();
}
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Impostor.Api.Innersloth
{
public enum Platforms
{
Unknown = 0,
StandaloneEpicPC = 1,
StandaloneSteamPC = 2,
StandaloneMac = 3,
StandaloneWin10 = 4,
StandaloneItch = 5,
IPhone = 6,
Android = 7,
Switch = 8,
Xbox = 9,
Playstation = 10,
}
}
@@ -1,6 +1,6 @@
namespace Impostor.Api.Innersloth
{
public enum ChatType
public enum QuickChatModes
{
FreeChatOrQuickChat = 1,
QuickChatOnly = 2,
-50
View File
@@ -1,50 +0,0 @@
using System.Collections.Generic;
using System.IO;
namespace Impostor.Api.Innersloth
{
public class RegionInfo
{
public RegionInfo(string name, string ping, IReadOnlyList<ServerInfo> servers)
{
Name = name;
Ping = ping;
Servers = servers;
}
public string Name { get; }
public string Ping { get; }
public IReadOnlyList<ServerInfo> Servers { get; }
public static RegionInfo Deserialize(BinaryReader reader)
{
var unknown = reader.ReadInt32();
var name = reader.ReadString();
var ping = reader.ReadString();
var servers = new List<ServerInfo>();
var serverCount = reader.ReadInt32();
for (var i = 0; i < serverCount; i++)
{
servers.Add(ServerInfo.Deserialize(reader));
}
return new RegionInfo(name, ping, servers);
}
public void Serialize(BinaryWriter writer)
{
writer.Write(0);
writer.Write(Name);
writer.Write(Ping);
writer.Write(Servers.Count);
foreach (var server in Servers)
{
server.Serialize(writer);
}
}
}
}
@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.IO;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Innersloth
{
public class RoleOptionsData
{
public bool ShapeshifterLeaveSkin { get; set; }
public byte ShapeshifterCooldown { get; set; } = 10;
public byte ShapeshifterDuration { get; set; } = 30;
public byte ScientistCooldown { get; set; } = 15;
public byte ScientistBatteryCharge { get; set; } = 5;
public byte GuardianAngelCooldown { get; set; } = 60;
public bool ImpostorsCanSeeProtect { get; set; }
public byte ProtectionDurationSeconds { get; set; } = 10;
public byte EngineerCooldown { get; set; } = 30;
public byte EngineerInVentMaxTime { get; set; } = 15;
public Dictionary<RoleTypes, RoleRate> RoleRates { get; } = new Dictionary<RoleTypes, RoleRate>();
public static RoleOptionsData Deserialize(ReadOnlySpan<byte> span)
{
var roleOptionsData = new RoleOptionsData();
var num = span.ReadInt32();
for (var i = 0; i < num; i++)
{
var key = (RoleTypes)span.ReadInt16();
var roleRate = new RoleRate(span.ReadByte(), span.ReadByte());
roleOptionsData.RoleRates[key] = roleRate;
}
roleOptionsData.ShapeshifterLeaveSkin = span.ReadBoolean();
roleOptionsData.ShapeshifterCooldown = span.ReadByte();
roleOptionsData.ShapeshifterDuration = span.ReadByte();
roleOptionsData.ScientistCooldown = span.ReadByte();
roleOptionsData.GuardianAngelCooldown = span.ReadByte();
roleOptionsData.EngineerCooldown = span.ReadByte();
roleOptionsData.EngineerInVentMaxTime = span.ReadByte();
roleOptionsData.ScientistBatteryCharge = span.ReadByte();
roleOptionsData.ProtectionDurationSeconds = span.ReadByte();
roleOptionsData.ImpostorsCanSeeProtect = span.ReadBoolean();
return roleOptionsData;
}
public static RoleOptionsData Deserialize(IMessageReader reader)
{
var roleOptionsData = new RoleOptionsData();
var num = reader.ReadPackedInt32();
for (var i = 0; i < num; i++)
{
var key = (RoleTypes)reader.ReadInt16();
var roleRate = new RoleRate(reader.ReadByte(), reader.ReadByte());
roleOptionsData.RoleRates[key] = roleRate;
}
roleOptionsData.ShapeshifterLeaveSkin = reader.ReadBoolean();
roleOptionsData.ShapeshifterCooldown = reader.ReadByte();
roleOptionsData.ShapeshifterDuration = reader.ReadByte();
roleOptionsData.ScientistCooldown = reader.ReadByte();
roleOptionsData.GuardianAngelCooldown = reader.ReadByte();
roleOptionsData.EngineerCooldown = reader.ReadByte();
roleOptionsData.EngineerInVentMaxTime = reader.ReadByte();
roleOptionsData.ScientistBatteryCharge = reader.ReadByte();
roleOptionsData.ProtectionDurationSeconds = reader.ReadByte();
roleOptionsData.ImpostorsCanSeeProtect = reader.ReadBoolean();
return roleOptionsData;
}
public void Serialize(IMessageWriter writer)
{
writer.WritePacked(RoleRates.Count);
foreach (var roleRate in RoleRates)
{
writer.Write((ushort)roleRate.Key);
writer.Write((byte)roleRate.Value.MaxCount);
writer.Write((byte)roleRate.Value.Chance);
}
writer.Write(ShapeshifterLeaveSkin);
writer.Write(ShapeshifterCooldown);
writer.Write(ShapeshifterDuration);
writer.Write(ScientistCooldown);
writer.Write(GuardianAngelCooldown);
writer.Write(EngineerCooldown);
writer.Write(EngineerInVentMaxTime);
writer.Write(ScientistBatteryCharge);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
public void Serialize(BinaryWriter writer)
{
writer.Write(RoleRates.Count);
foreach (var roleRate in RoleRates)
{
writer.Write((ushort)roleRate.Key);
writer.Write((byte)roleRate.Value.MaxCount);
writer.Write((byte)roleRate.Value.Chance);
}
writer.Write(ShapeshifterLeaveSkin);
writer.Write(ShapeshifterCooldown);
writer.Write(ShapeshifterDuration);
writer.Write(ScientistCooldown);
writer.Write(GuardianAngelCooldown);
writer.Write(EngineerCooldown);
writer.Write(EngineerInVentMaxTime);
writer.Write(ScientistBatteryCharge);
writer.Write(ProtectionDurationSeconds);
writer.Write(ImpostorsCanSeeProtect);
}
public readonly struct RoleRate
{
public readonly int MaxCount;
public readonly int Chance;
public RoleRate(int maxCount, int chance)
{
MaxCount = maxCount;
Chance = chance;
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace Impostor.Api.Innersloth
{
public enum RoleTypes : ushort
{
Crewmate,
Impostor,
Scientist,
Engineer,
GuardianAngel,
Shapeshifter,
}
}
-39
View File
@@ -1,39 +0,0 @@
using System.IO;
using System.Net;
namespace Impostor.Api.Innersloth
{
public class ServerInfo
{
public ServerInfo(string name, string ip, ushort port)
{
Name = name;
Ip = ip;
Port = port;
}
public string Name { get; }
public string Ip { get; }
public ushort Port { get; }
public static ServerInfo Deserialize(BinaryReader reader)
{
var name = reader.ReadString();
var ip = new IPAddress(reader.ReadBytes(4)).ToString();
var port = reader.ReadUInt16();
var unknown = reader.ReadInt32();
return new ServerInfo(name, ip, port);
}
public void Serialize(BinaryWriter writer)
{
writer.Write(Name);
writer.Write(IPAddress.Parse(Ip).GetAddressBytes());
writer.Write(Port);
writer.Write(0);
}
}
}
@@ -67,5 +67,39 @@
Specimens = 28,
BoilerRoom = 29,
VaultRoom = 30,
Cockpit = 31,
Armory = 32,
Kitchen = 33,
ViewingDeck = 34,
HallOfPortraits = 35,
CargoBay = 36,
Ventilation = 37,
Showers = 38,
Engine = 39,
Brig = 40,
MeetingRoom = 41,
Records = 42,
Lounge = 43,
GapRoom = 44,
MainHall = 45,
Medical = 46,
}
}
@@ -0,0 +1,9 @@
namespace Impostor.Api.Innersloth
{
public enum TaskCategories : byte
{
CommonTask,
LongTask,
ShortTask,
}
}
+19 -1
View File
@@ -1,4 +1,4 @@
namespace Impostor.Api.Innersloth
namespace Impostor.Api.Innersloth
{
public enum TaskTypes : uint
{
@@ -45,5 +45,23 @@
AlignTelescope = 40,
RecordTemperature = 41,
RebootWifi = 42,
PolishRuby = 43,
ResetBreakers = 44,
Decontaminate = 45,
MakeBurger = 46,
UnlockSafe = 47,
SortRecords = 48,
PutAwayPistols = 49,
FixShower = 50,
CleanToilet = 51,
DressMannequin = 52,
PickUpTowels = 53,
RewindTapes = 54,
StartFans = 55,
DevelopPhotos = 56,
GetBiggolSword = 57,
PutAwayRifles = 58,
StopCharles = 59,
VentCleaning = 60,
}
}
+13 -1
View File
@@ -4,7 +4,19 @@
{
public static bool IsCharAllowed(char i)
{
return i == ' ' || (i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || (i >= '0' && i <= '9') || (i >= 'À' && i <= 'ÿ') || (i >= 'Ѐ' && i <= 'џ') || (i >= 'ㄱ' && i <= 'ㆎ') || (i >= '가' && i <= '힣');
return i == ' ' ||
(i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
// U+00C0 to U+00FF (Latin-1 Supplement)
(i >= 'À' && i <= 'ÿ') ||
// U+0400 to U+045F (Cyrillic)
(i >= 'Ѐ' && i <= 'џ') ||
// U+2C61 to U+D7A3 (CJK)
(i >= 'ⱡ' && i <= '힣');
}
}
}
@@ -1,48 +0,0 @@
namespace Impostor.Api.Innersloth
{
public enum VentLocation : uint
{
// Skeld
SkeldAdmin = 0,
SkeldRightHallway = 1,
SkeldCafeteria = 2,
SkeldElectrical = 3,
SkeldUpperEngine = 4,
SkeldSecurity = 5,
SkeldMedbay = 6,
SkeldWeapons = 7,
SkeldLowerReactor = 8,
SkeldLowerEngine = 9,
SkeldShields = 10,
SkeldUpperReactor = 11,
SkeldUpperNavigation = 12,
SkeldLowerNavigation = 13,
// Mira HQ
MiraBalcony = 1,
MiraCafeteria = 2,
MiraReactor = 3,
MiraLaboratory = 4,
MiraOffice = 5,
MiraAdmin = 6,
MiraGreenhouse = 7,
MiraMedbay = 8,
MiraDecontamination = 9,
MiraLockerRoom = 10,
MiraLaunchpad = 11,
// Polus
PolusSecurity = 0,
PolusElectrical = 1,
PolusO2 = 2,
PolusCommunications = 3,
PolusOffice = 4,
PolusAdmin = 5,
PolusLaboratory = 6,
PolusLava = 7,
PolusStorage = 8,
PolusRightStabilizer = 9,
PolusLeftStabilizer = 10,
PolusOutsideAdmin = 11,
}
}
@@ -0,0 +1,7 @@
namespace Impostor.Api.Net.Custom
{
public interface ICustomMessage
{
byte Id { get; }
}
}
@@ -0,0 +1,18 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Impostor.Api.Net.Custom
{
public interface ICustomMessageManager<T>
where T : ICustomMessage
{
bool TryGet(byte id, [MaybeNullWhen(false)] out T message);
/// <summary>
/// Register a custom message.
/// </summary>
/// <param name="message"><typeparamref name="T"/> message.</param>
/// <returns>Disposable that unregisters the message.</returns>
IDisposable Register(T message);
}
}
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
public interface ICustomRootMessage : ICustomMessage
{
ValueTask HandleMessageAsync(IClient client, IMessageReader reader, MessageType messageType);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net.Custom
{
public interface ICustomRpc : ICustomMessage
{
ValueTask<bool> HandleRpcAsync(IInnerNetObject innerNetObject, IClientPlayer sender, IClientPlayer? target, IMessageReader reader);
}
}
+18 -4
View File
@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Net.Messages;
using Impostor.Api.Reactor;
namespace Impostor.Api.Net
{
@@ -29,9 +28,14 @@ namespace Impostor.Api.Net
string Name { get; }
/// <summary>
/// Gets mods sent by client in modded handshake.
/// Gets the language.
/// </summary>
ISet<Mod> Mods { get; }
Language Language { get; }
/// <summary>
/// Gets the quick chat mode.
/// </summary>
QuickChatModes ChatMode { get; }
/// <summary>
/// Gets the connection of the client.
@@ -61,6 +65,16 @@ namespace Impostor.Api.Net
/// </summary>
IClientPlayer? Player { get; }
/// <summary>
/// Gets the version of the game the client is using.
/// </summary>
int GameVersion { get; }
/// <summary>
/// Gets platform specific data of the <see cref="IClient" />.
/// </summary>
PlatformSpecificData PlatformSpecificData { get; }
ValueTask<bool> ReportCheatAsync(CheatContext context, string message);
ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType);
+7 -1
View File
@@ -24,6 +24,11 @@ namespace Impostor.Api.Net
/// </summary>
IClient? Client { get; set; }
/// <summary>
/// Gets the average ping of the client.
/// </summary>
float AveragePing { get; }
/// <summary>
/// Sends a message writer to the connection.
/// </summary>
@@ -35,7 +40,8 @@ namespace Impostor.Api.Net
/// Disconnects the client and invokes the disconnect handler.
/// </summary>
/// <param name="reason">A reason.</param>
/// <param name="writer">A message to send with disconnect packet.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask DisconnectAsync(string? reason);
ValueTask DisconnectAsync(string? reason, IMessageWriter? writer = null);
}
}
+1
View File
@@ -1,4 +1,5 @@
using Impostor.Api.Net.Inner.Objects;
using Impostor.Api.Net.Inner.Objects.ShipStatus;
namespace Impostor.Api.Net.Inner
{
@@ -1,9 +1,13 @@
namespace Impostor.Api.Net.Inner
using Impostor.Api.Games;
namespace Impostor.Api.Net.Inner
{
public interface IInnerNetObject
{
public uint NetId { get; }
public int OwnerId { get; }
public IGame Game { get; }
}
}
@@ -1,6 +1,59 @@
namespace Impostor.Api.Net.Inner.Objects
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Impostor.Api.Events.Player;
namespace Impostor.Api.Net.Inner.Objects
{
public interface IInnerMeetingHud : IInnerNetObject
{
public interface IPlayerVoteArea
{
/// <summary>
/// Gets the player info of this vote state.
/// </summary>
IInnerPlayerInfo TargetPlayer { get; }
/// <summary>
/// Gets a value indicating whether the player is a dead.
/// </summary>
bool IsDead { get; }
/// <summary>
/// Gets a value indicating whether the player started this meeting.
/// </summary>
bool DidReport { get; }
/// <summary>
/// Gets a value indicating whether the player voted.
/// </summary>
bool DidVote { get; }
/// <summary>
/// Gets the vote type.
/// </summary>
/// <remarks>
/// Null when <see cref="DidVote" /> is false.
/// </remarks>
[MemberNotNullWhen(true, nameof(DidVote))]
public VoteType? VoteType { get; }
/// <summary>
/// Gets the player voted for.
/// </summary>
/// <remarks>
/// Null when <see cref="VoteType" /> isn't <see cref="F:Impostor.Api.Events.Player.VoteType.Player"/>.
/// </remarks>
public IInnerPlayerControl? VotedFor { get; }
}
/// <summary>
/// Gets states of players taking part in this meeting.
/// </summary>
IReadOnlyCollection<IPlayerVoteArea> PlayerStates { get; }
/// <summary>
/// Gets the player that started the meeting.
/// </summary>
IInnerPlayerInfo? Reporter { get; }
}
}
@@ -49,25 +49,25 @@ namespace Impostor.Api.Net.Inner.Objects
/// Sets the hat of the current <see cref="IInnerPlayerControl" />.
/// Visible to all players.
/// </summary>
/// <param name="hatType">An hat for the player.</param>
/// <param name="hatId">An hat for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetHatAsync(HatType hatType);
ValueTask SetHatAsync(string hatId);
/// <summary>
/// Sets the pet of the current <see cref="IInnerPlayerControl" />.
/// Visible to all players.
/// </summary>
/// <param name="petType">A pet for the player.</param>
/// <param name="petId">A pet for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetPetAsync(PetType petType);
ValueTask SetPetAsync(string petId);
/// <summary>
/// Sets the skin of the current <see cref="IInnerPlayerControl" />.
/// Visible to all players.
/// </summary>
/// <param name="skinType">A skin for the player.</param>
/// <param name="skinId">A skin for the player.</param>
/// <returns>Task that must be awaited.</returns>
ValueTask SetSkinAsync(SkinType skinType);
ValueTask SetSkinAsync(string skinId);
/// <summary>
/// Send a chat message as the current <see cref="IInnerPlayerControl" />.
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.Customization;
@@ -12,26 +12,6 @@ namespace Impostor.Api.Net.Inner.Objects
/// </summary>
string PlayerName { get; }
/// <summary>
/// Gets the color of the player.
/// </summary>
ColorType Color { get; }
/// <summary>
/// Gets the hat of the player.
/// </summary>
HatType Hat { get; }
/// <summary>
/// Gets the pet of the player.
/// </summary>
PetType Pet { get; }
/// <summary>
/// Gets the skin of the player.
/// </summary>
SkinType Skin { get; }
/// <summary>
/// Gets a value indicating whether the player is an impostor.
/// </summary>
@@ -42,6 +22,12 @@ namespace Impostor.Api.Net.Inner.Objects
/// </summary>
bool IsDead { get; }
Dictionary<PlayerOutfitType, PlayerOutfit> Outfits { get; }
PlayerOutfitType CurrentOutfitType { get; set; }
PlayerOutfit CurrentOutfit { get; }
/// <summary>
/// Gets the reason why the player is dead in the current game.
/// </summary>
@@ -50,5 +36,7 @@ namespace Impostor.Api.Net.Inner.Objects
IEnumerable<ITaskInfo> Tasks { get; }
DateTimeOffset LastMurder { get; }
uint PlayerLevel { get; }
}
}
@@ -1,4 +1,5 @@
using Impostor.Api.Innersloth;
using System.Threading.Tasks;
using Impostor.Api.Innersloth;
namespace Impostor.Api.Net.Inner.Objects
{
@@ -6,8 +7,14 @@ namespace Impostor.Api.Net.Inner.Objects
{
uint Id { get; }
TaskTypes Type { get; }
ITask? Task { get; }
bool Complete { get; }
/// <summary>
/// Sets the task as complete.
/// </summary>
/// <returns>Task that must be awaited.</returns>
ValueTask CompleteAsync();
}
}
@@ -0,0 +1,6 @@
namespace Impostor.Api.Net.Inner.Objects.ShipStatus
{
public interface IInnerAirshipStatus : IInnerShipStatus
{
}
}
Loaded 100 of 313 files, more files were not shown because too many files have changed in this diff. Show more