Compare commits

..

1131 Commits

Author SHA1 Message Date
Paul
0b749ff8bb makes prototypeinheritance opt in 2021-03-05 11:13:00 +01:00
Paul
069fa89fcb adds Try variants to FirstOrNull & FirstOrDefault
fixes ientity serialization when loading the map
2021-03-05 10:07:18 +01:00
Paul Ritter
80f9f24243 Serialization v3 aka constant suffering (#1606)
* oops

* fixes serialization il

* copytest

* typo & misc fixes

* 139 moment

* boxing

* mesa dum

* stuff

* goodbye bad friend

* last commit before the big (4) rewrite

* adds datanodes

* kills yamlobjserializer in favor of the new system

* adds more serializers, actually implements them & removes most of the last of the old system

* changed yamlfieldattribute namespace

* adds back iselfserialize

* refactors consts&flags

* renames everything to data(field/definition)

* adds afterserialization

* help

* dataclassgen

* fuggen help me mannen

* Fix most errors on content

* Fix engine errors except map loader

* maploader & misc fix

* misc fixes

* thing

* help

* refactors datanodes

* help me mannen

* Separate ITypeSerializer into reader and writer

* Convert all type serializers

* priority

* adds alot

* il fixes

* adds robustgen

* argh

* adds array & enum serialization

* fixes dataclasses

* adds vec2i / misc fixes

* fixes inheritance

* a very notcursed todo

* fixes some custom dataclasses

* push dis

* Remove data classes

* boutta box

* yes

* Add angle and regex serializer tests

* Make TypeSerializerTest abstract

* sets up ioc etc

* remove pushinheritance

* fixes

* Merge fixes, fix yaml hot reloading

* General fixes2

* Make enum serialization ignore case

* Fix the tag not being copied in data nodes

* Fix not properly serializing flag enums

* Fix component serialization on startup

* Implement ValueDataNode ToString

* Serialization IL fixes, fix return and string equality

* Remove async from prototype manager

* Make serializing unsupported node as enum exception more descriptive

* Fix serv3 tryread casting to serializer instead of reader

* Add constructor for invalid node type exception

* Temporary fix for SERV3: Turn populate delegate into regular code

* Fix not copying the data of non primitive types

* Fix not using the data definition found in copying

* Make ISerializationHooks require explicit implementations

* Add test for serialization inheritance

* Improve IsOverridenIn method

* Fix error message when a data definition is null

* Add method to cast a read value in Serv3Manager

* Rename IServ3Manager to ISerializationManager

* Rename usages of serv3manager, add generic copy method

* Fix IL copy method lookup

* Rename old usages of serv3manager

* Add ITypeCopier

* resistance is futile

* we will conquer this codebase

* Add copy method to all serializers

* Make primitive mismatch error message more descriptive

* bing bong im going to freacking heck

* oopsie moment

* hello are you interested in my wares

* does generic serializers under new architecture

* Convert every non generic serializer to the new format, general fixes

* Update usgaes of generic serializers, cleanup

* does some pushinheritance logic

* finishes pushinheritance FRAMEWORK

* shed

* Add box2, color and component registry serializer tests

* Create more deserialized types and store prototypes with their deserialized results

* Fixes and serializer updates

* Add serialization manager extensions

* adds pushinheritance

* Update all prototypes to have a parent and have consistent id/parent properties

* Fix grammar component serialization

* Add generic serializer tests

* thonk

* Add array serializer test

* Replace logger warning calls with exceptions

* fixes

* Move redundant methods to serialization manager extensions, cleanup

* Add array serialization

* fixes context

* more fixes

* argh

* inheritance

* this should do it

* fixes

* adds copiers & fixes some stuff

* copiers use context v1

* finishing copy context

* more context fixes

* Test fixes

* funky maps

* Fix server user interface component serialization

* Fix value tuple serialization

* Add copying for value types and arrays. Fix copy internal for primitives, enums and strings

* fixes

* fixes more stuff

* yes

* Make abstract/interface skips debugs instead of warnings

* Fix typo

* Make some dictionaries readonly

* Add checks for the serialization manager initializing and already being initialized

* Add base type required and usage for MeansDataDefinition and ImplicitDataDefinitionForInheritorsAttribute

* copy by ref

* Fix exception wording

* Update data field required summary with the new forbidden docs

* Use extension in map loader

* wanna erp

* Change serializing to not use il temporarily

* Make writing work with nullable types

* pushing

* check

* cuddling slaps HARD

* Add serialization priority test

* important fix

* a serialization thing

* serializer moment

* Add validation for some type serializers

* adds context

* moar context

* fixes

* Do the thing for appearance

* yoo lmao

* push haha pp

* Temporarily make copy delegate regular c# code

* Create deserialized component registry to handle not inheriting conflicting references

* YAML LINTER BABY

* ayes

* Fix sprite component norot not being default true like in latest master

* Remove redundant todos

* Add summary doc to every ISerializationManager method

* icon fixes

* Add skip hook argument to readers and copiers

* Merge fixes

* Fix ordering of arguments in read and copy reflection call

* Fix user interface components deserialization

* pew pew

* i am going to HECK

* Add MustUseReturnValue to copy-over methods

* Make serialization log calls use the same sawmill

* gamin

* Fix doc errors in ISerializationManager.cs

* goodbye brave soldier

* fixes

* WIP merge fixes and entity serialization

* aaaaaaaaaaaaaaa

* aaaaaaaaaaaaaaa

* adds inheritancebehaviour

* test/datafield fixes

* forgot that one

* adds more verbose validation

* This fixes the YAML hot reloading

* Replace yield break with Enumerable.Empty

* adds copiers

* aaaaaaaaaaaaa

* array fix
priority fix
misc fixes

* fix(?)

* fix.

* funny map serialization (wip)

* funny map serialization (wip)

* Add TODO

* adds proper info the validation

* Make yaml linter 5 times faster (~80% less execution time)

* Improves the error message for missing fields in the linter

* Include component name in unknown component type error node

* adds alwaysrelevant usa

* fixes mapsaving

* moved surpressor to analyzers proj

* warning cleanup & moves surpressor

* removes old msbuild targets

* Revert "Make yaml linter 5 times faster (~80% less execution time)"

This reverts commit 2ee4cc2c26.

* Add serialization to RobustServerSimulation and mock reflection methods
Fixes container tests

* Fix nullability warnings

* Improve yaml linter message feedback

* oops moment

* Add IEquatable, IComparable, ToString and operators to DataPosition
Rename it to NodeMark
Make it a readonly struct

* Remove try catch from enum parsing

* Make dependency management in serialization less bad

* Make dependencies an argument instead of a property on the serialization manager

* Clean up type serializers

* Improve validation messages and resourc epath checking

* Fix sprite error message

* reached perfection

Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Vera Aguilera Puerto <zddm@outlook.es>
2021-03-04 15:59:14 -08:00
Pieter-Jan Briers
93018c9843 Silence localization warnings on client again. 2021-03-03 16:02:30 +01:00
Pieter-Jan Briers
e2675271d0 Parallelize assembly sandbox checking harder. 2021-03-03 16:02:12 +01:00
Pieter-Jan Briers
d1f7edecef Use Directory.EnumerateFiles in PathHelpers.GetFiles.
Significant improvement in startup time.
2021-03-03 10:52:05 +01:00
Pieter-Jan Briers
b5a3c0b988 Do not load files under Locale/ not ending with .ftl.
Will ignore stuff like .DS_Store/.directory/thumbs.db
2021-03-02 21:22:44 +01:00
Acruid
06e62b031a SoundSystem (#1604)
* Adds the SoundSystem static proxy class for the AudioSystem.
Added a shared IAudioSystem interface for the future.

* Moved ConnectedClient property from IPlayerSession down to ICommonSession.

* Connected up the SoundSystem to the client/server AudioSystems.

* Converted client calls over to the new system.

* Marked the old serverside functions to play sound obsolete, use the new ones from the IAudioSystem.

* Added ISharedPlayerManager to the IoC registration.
2021-03-01 20:22:28 -08:00
Acruid
24707b7385 Shared Containers (#1579)
* Added a basic server simulation framework for help with tests.

* Moved as much as possible to Robust.Shared/Containers.
Moved ContainerSlot from content to engine.

* Moved ClientContainer to shared.

* Merged client/server ContainerManagerComponents into a single shared version.

* ContainerManagerComponent is now implicitly registered with the attributes.

* Migrated to 2021 serialization technology.

* Existing Unit Tests work.

* More tests coverage.
Fixed bug with transferring items between containers.

* Container Type info is now sent over the network.

* Merge client/server container systems.

* Code cleanup.

* Attempted to fix dictionary serialization.
Logs warning when trying to check if an unknown GridId is paused.

* Remove OldCode.
2021-03-01 15:19:59 -08:00
Pieter-Jan Briers
ab95f39f9f Localize SS14Window 2021-03-01 00:45:36 +01:00
Pieter-Jan Briers
cdd38abab5 Fix two shutdown crashes by removing IDisposable managers. 2021-02-28 23:10:03 +01:00
Pieter-Jan Briers
d751c0b3ab Revert "Physics (#1602)"
This reverts commit fefcc7cba3.
2021-02-28 18:45:18 +01:00
Pieter-Jan Briers
2ace0e9e5a Expose Patreon tier info from auth server. 2021-02-28 18:45:01 +01:00
Pieter-Jan Briers
31716f5104 Work around Roslyn scripting bug with ref structs. 2021-02-28 18:45:01 +01:00
metalgearsloth
fefcc7cba3 Physics (#1602)
* Physics worlds

* Paul's a good boy

* Build working

* Ingame and not lagging to hell

* Why didn't you commit ahhhhh

* Hard collisions working

* Solver parity

* Decent broadphase work done

* BroadPhase outline done

* BroadPhase working

* waiting for pvs

* Fix static PVS AABB

* Stop static bodies from awakening

* Optimise a bunch of stuff

* Even more broadphase stuff

* I'm fucking stupid

* Optimise fixture updates

* Collision solver start

* Building

* A is for Argumentative

* Fix contact caching island flags

* Circle shapes actually workeded

* Damping

* DS2 consumables only

* Slightly more stable

* Even slightlier more stablier

* VV your heart out

* Initial joint support

* 90% of joints I just wanted to push as I'd scream if I lost progress

* JOINT PURGATORY

* Joints barely functional lmao

* Okay these joints slightly more functional

* Remove station FrictionJoint

* Also that

* Some Box2D ports

* Cleanup mass

* Edge shape

* Active contacts

* Fix active contacts

* Optimise active contacts even more

* Boxes be stacking

* I would die for smug oh my fucking god

* In which everything is fixed

* Distance joints working LETS GO

* Remove frequency on distancejoint

* Fix some stuff and break joints

* Crashing fixed mehbeh

* ICollideSpecial and more resilience

* auto-clear

* showbb vera

* Slap that TODO in there

* Fix restartround crash

* Random fixes

* Fix fixture networking

* Add intersection method for broadphase

* Fix contacts

* Licenses done

* Optimisations

* Fix wall clips

* Config caching for island

* allocations optimisations

* Optimise casts

* Optimise events queue for physics

* Contact manager optimisations

* Optimise controllers

* Sloth joint or something idk

* Controller graph

* Remove content cvar

* Random cleanup

* Finally remove VirtualController

* Manifold structs again

* Optimise this absolute retardation

* Optimise

* fix license

* Cleanup physics interface

* AHHHHHHHHHHHHH

* Fix collisions again

* snivybus

* Fix potential nasty manifold bug

* Tests go snivy

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-03-01 03:09:36 +11:00
Paul
30df989e8d Merge branch 'serialization_v3_nodataclasses' of https://github.com/PaulRitter/RobustToolbox into master 2021-02-28 15:55:26 +01:00
Acruid
86bfea6bd4 ICommonSession Improvements + Player Filter (#1600)
* Removed IBaseSession, pushed all members down to ICommonSession.

* Pulled all members of client IPlayerSession into ICommonSession.
Marked client IPlayerSession as obsolete, use the base ICommonSession.

* Restricted setter access for properties in ICommonSession, only engine should be setting them.

* Fixed ping implementation on server.

* Moved AttachedEntityUid to ICommonSession.

* Added a shared IPlayerManager and pulled some common properties down to it.

* Added a shared player Filter class that holds a set of recipients in a networked call. Very useful for selecting recipients in a shared context.
2021-02-27 20:42:54 -08:00
Paul
d890f168c2 Spawner windows remember positions - engine commit 2021-02-27 12:27:46 +01:00
Paul
f888a810bf fixes that pesky warning 2021-02-27 11:58:51 +01:00
tmtmtl30
16249a4dde doubles default gain value (#1593) 2021-02-26 20:54:43 -08:00
Manel Navola
e33488ba55 Implemented erasing rectangular areas (#1419)
* Added support for erasing rectangular areas

* Apply suggestions from code review

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Switched sending start coordinate + end coordinate to sending start coordinate + rect selection size for preventing different parented positions, general code improvements

* Rewritten certain code part so the checks pass

* Added unshaded shader to rect erasing

* Tweaked alpha of erasing rectangle for better visualizing

Co-authored-by: Manel Navola <ManelNavola@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2021-02-26 20:52:12 -08:00
RemieRichards
bfe6eeddb1 Localization Fixes. Stop double-localizing localizationID-sourced names, PROPER returning "True" or "False" instead of "true" or "false" 2021-02-27 01:04:04 +00:00
RemieRichards
7f540e741c Add myself to CODEOWNERS for fluent translations. 2021-02-25 20:30:57 +00:00
Pieter-Jan Briers
b7855f5af5 Fix reloading localizations. 2021-02-25 20:47:17 +01:00
Pieter-Jan Briers
91391e1205 Update NetSerializer submodule 2021-02-25 12:06:28 +01:00
Pieter-Jan Briers
d5199ec459 Update NuGet packages. 2021-02-25 12:06:05 +01:00
Vera Aguilera Puerto
e1e6f4fd10 ContainerHelpers EmptyContainer now has an argument to attach removed entities to grid or map 2021-02-25 11:43:09 +01:00
Leo
e5b6fccf67 Add a scroll speed property to ScrollContainer (#1590)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-02-25 10:39:53 +00:00
RemberBL
95a912c329 Adds args.Handle(); into UI code for scrolling (#1595) 2021-02-25 11:08:19 +01:00
Pieter-Jan Briers
2b4833fc4e Allow content to read assembly versions in sandbox. 2021-02-24 12:18:44 +01:00
Pieter-Jan Briers
b814fc851a Fix more scrollbar DPI scaling bugs. 2021-02-24 12:18:29 +01:00
Pieter-Jan Briers
e87863203b Use DataFieldCached for AppearanceComponent.
What could go wrong?
2021-02-23 23:56:41 +01:00
Pieter-Jan Briers
33b66d9e18 Fix OpenCentered and OpenToLeft window methods. 2021-02-23 23:24:58 +01:00
Pieter-Jan Briers
fd406f7897 Selector-based VV windows have correct size.
Fixes #1594.
2021-02-23 23:10:58 +01:00
Pieter-Jan Briers
7a836d1018 Work around broken nullability.
Revert "Fix nullability errors"

This reverts commit a7f31f9ebf.

Revert "NotNullWhen()"

This reverts commit b332644d48.

Work around broken nullability.
2021-02-23 23:07:19 +01:00
Alex Evgrashin
393c15c44a Post shader will use real sprite bounding box (#1536)
Co-authored-by: Alex Evgrashin <evgrashin.adl@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-02-23 22:54:48 +01:00
Pieter-Jan Briers
a7f31f9ebf Fix nullability errors 2021-02-23 22:53:38 +01:00
RemieRichards
b332644d48 NotNullWhen() 2021-02-23 21:40:33 +00:00
RemieRichards
510f7c0e7c Merge branch 'master' of https://github.com/space-wizards/RobustToolbox into localization_grammar 2021-02-23 21:33:06 +00:00
RemieRichards
fdd05e3d3a Fix GrammarComponent gender parsing, Add tests for GENDER() function (which covers custom types (Enum) and custom functions (GENDER)) 2021-02-23 21:31:13 +00:00
Pieter-Jan Briers
6d41958853 Fix nullability of TryIndex<T>. 2021-02-23 22:25:48 +01:00
Pieter-Jan Briers
cecc4dfcf2 Improve SharedTransformSystem:
Do not fire events for deleted entities.
Optimize to remove allocations & LINQ.
2021-02-23 22:05:49 +01:00
Pieter-Jan Briers
4ac40f2e90 Make norot on sprites default for the time being.
To band aid the pulling issues.
2021-02-23 21:32:00 +01:00
Pieter-Jan Briers
3e12d44173 Bool/enum/entity handling for localization parameters. 2021-02-23 20:59:21 +01:00
RemieRichards
a42b39bd84 Adds GENDER(), PROPER() and ATTRIB() localization functions, GrammarComponent. 2021-02-23 19:53:56 +00:00
DrSmugleaf
22affccf24 Add individual layer offset (#1583)
* Add individual layer offset

* Fix error message

* Bring back layer offsetting
2021-02-23 12:55:45 +01:00
Pieter-Jan Briers
028724c47b Localization improvements:
*Allow content to define localization functions.
* Add rldloc command to reload localizations.
* Doc comments
* Error handling
* Parallelize loading of localization files, since I can only assume we'll have a lot eventually.
* Type system stuff to allow content to pass custom data types into fluent.
* Code cleanup.
2021-02-23 11:35:54 +01:00
Pieter-Jan Briers
0114bff2fc Add IFormattable to sandbox whitelist. 2021-02-23 11:27:51 +01:00
Pieter-Jan Briers
4ddbd644eb Add helper method to set up logging inside unit tests. 2021-02-23 11:27:42 +01:00
Pieter-Jan Briers
f0366531ef Inject the csi directly into my master. 2021-02-23 01:39:33 +01:00
Pieter-Jan Briers
6bd5814f4a Automatically fetch names and descs from loc. 2021-02-22 11:11:11 +01:00
Pieter-Jan Briers
78c132fdab Mute loc warnings for the time being. 2021-02-22 08:57:30 +01:00
Remie Richards
460cf57d7c Fluent Localization (#1584) 2021-02-22 00:36:02 +01:00
Pieter-Jan Briers
a3190a8aca Improvements to SpriteComponent for new angle changes: (#1589)
1. Fixes CopyFrom with new rotation parameters.
2. Adds a couple APIs for ClickableComponent content side.
2021-02-22 00:30:16 +01:00
Pieter-Jan Briers
6921fb2fbf Make UserInterfaceManager not dispose root control on game shutdown.
No real reason to do this and it only risks breaking something.
2021-02-21 23:52:09 +01:00
Fortune117
9954d571de Fix for Crash Caused by the Entity Spawn Menu (#1588) 2021-02-21 20:16:01 +01:00
Pieter-Jan Briers
17fe000a1e Fix math tests due to angle/direction changes. 2021-02-21 20:06:39 +01:00
Pieter-Jan Briers
fba415e765 Bit of work to make Direction.South == Angle.Zero.
This makes Direction no longer follow a cartesian trig circle but oh well. Also helper methods to work with this.

Math tests currently fail, pushing this so Acruid can see about fixing SpriteComponent.
2021-02-21 19:47:42 +01:00
Pieter-Jan Briers
583b7ebf38 WPF layout (#1581) 2021-02-21 12:28:13 +01:00
Acruid
771a256925 Fixes bug with an exception being throw when trying to overwrite a deleted Component. (#1587)
Entity now uses constructor injection instead of property injection.
2021-02-20 23:30:09 -08:00
Acruid
ae79e89347 Added a shared PointLightComponent interface. (#1585)
* Added a shared PointLightComponent interface.

* Fix unit tests.
2021-02-20 16:06:34 -08:00
Acruid
6c7eeb95eb Marks Register and RegisterReference obsolete in IComponentFactory. (#1582) 2021-02-20 12:18:37 -08:00
Acruid
de0bd1887f Sprite Rendering Bugfixes (#1551)
* Added documentation to Clyde on the sprite rendering calls.

* Added a rotation debug entity.

* Non-directional RSIs and raw textures are now rotated properly.

* Directional RSIs and Sprite Smoothing work.

* Remove the Directional flag usages.

* Supports layers with different numbers of directions.

* Fixes window rendering.
2021-02-20 11:06:08 -08:00
metalgearsloth
eb3a815d48 Remove AiLogicProcessor (#1568)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-19 21:52:32 -08:00
DrSmugleaf
e2a4dcdff1 Fix comparing by name and not ID for entity prototype updates (#1578) 2021-02-20 02:41:51 +01:00
DrSmugleaf
68b0d7bf2e Fix not clearing the queue after hot reload (#1576) 2021-02-20 01:43:56 +01:00
DrSmugleaf
a9b163992b Fix and add test for PrototypeManager LoadString (#1574) 2021-02-20 01:43:43 +01:00
DrSmugleaf
2409965cf8 Fix build (#1575) 2021-02-20 00:15:43 +01:00
DrSmugleaf
eada37378a Add YAML hot reloading (#1571)
* Implement hot reloading for entity prototypes

* Implement automatic prototype hot-reloading

* Merge fixes

* Add yaml hot reloading and a message to notify the client

* Add reloading only changed files, remove cooldown, add retries and remove IPrototype

* Remove reload command

* Make the client listen for reloads instead and only when focused

* Fix errors

* Only queue a reload when the queue has items in it

* Make fails after 10 retries log instead of throw if reloading

Co-authored-by: Jackson Lewis <inquisitivepenguin@protonmail.com>
2021-02-20 00:02:04 +01:00
DrSmugleaf
0f1da1ba2a Add window focused callback to Clyde (#1573) 2021-02-19 22:10:03 +01:00
Acruid
e0cdcd228e Fixed Timer Namespace in unit tests. 2021-02-18 20:35:34 -08:00
Acruid
fdb5e014b5 PauseManager moved to Shared (#1553)
* Moved IPauseManager from server to shared.

* Moved ITimerManager from Timers to Timing.

* Added missing IConsoleHost to server/client RegisterIoC. Tests work again.
2021-02-18 20:12:26 -08:00
DrSmugleaf
cefcad775b Make addcomp and rmcomp give better feedback and case insensitive (#1570)
* Make addcomp and rmcomp case insensitive

* Fix up names

* Make addcomp and rmcomp give better feedback

* Make addcomp and rmcomp less fail happy
2021-02-18 20:01:14 -08:00
Vera Aguilera Puerto
e40feac1f1 Adds VV autorefresh when right-clicking the refresh button. (#1558)
* Adds VV autorefresh when right-clicking the refresh button.

* cancel token on close

* button tooltip
2021-02-18 00:14:11 -08:00
DrSmugleaf
3ef4ac7452 Make component states dependant on the player getting them (#1569) 2021-02-17 23:48:17 -08:00
Pieter-Jan Briers
93bf1b09e7 Fix disconnecting while connecting causes you to be locked out of the server. 2021-02-17 23:22:11 +01:00
DrSmugleaf
a1e557e870 Add IPrototypeManager method to load a string (#1567) 2021-02-17 13:20:39 -08:00
Pieter-Jan Briers
864adb7445 Add DateTimeStyles to sandbox. 2021-02-17 11:52:36 +01:00
mirrorcult
9e3f3f0c1c vec2i serializer (#1563)
Co-authored-by: cyclowns <cyclowns@protonmail.ch>
2021-02-16 12:19:45 -08:00
DrSmugleaf
a40c4a435c Fix file not found exceptions when starting up the game with a debugger (#1562)
* Fix exceptions when starting up the game

* Remove try catches
2021-02-16 20:05:22 +01:00
DrSmugleaf
17182dd0e8 Engine PR for enabling nullability in Content.Client (#1565) 2021-02-16 20:05:06 +01:00
DrSmugleaf
d8b50044a2 Add (de)serialization for immutable lists (#1549) 2021-02-16 20:04:28 +01:00
Pieter-Jan Briers
4dc396e73d Fixes warning in TypePropertySerialization_Test.cs 2021-02-16 09:20:06 +01:00
Pieter-Jan Briers
6ae0b0e892 Fix [GenerateTypedNameReferences] with sealed types.
Fixes #1546
2021-02-16 09:19:57 +01:00
Pieter-Jan Briers
7162ca3456 Probably fix the bug where people get locked out of the server due to duplicate connction attempts. 2021-02-16 09:02:14 +01:00
Pieter-Jan Briers
1b44c1a1b8 Allow NotImplementedException in sandbox. 2021-02-15 17:57:38 +01:00
Clyybber
5b80b33e00 Change GetFileSystemInfos to EnumerateFileSystemInfos for iteration (#1561) 2021-02-15 16:26:16 +01:00
DrSmugleaf
f05c1b2395 Add Attribute generic constraint to IReflectionManager.FindTypesWithAttribute (#1548) 2021-02-14 02:14:00 +01:00
Pieter-Jan Briers
d9b2c73440 XamlUI improvements.
1. Add XAML namespaces https://spacestation14.io with Avalonia hacks.
2. Make markup extensions work with Avalonia hacks.
3. Add LocExtension for localized strings.
4. Add Vector2 parsing type converter to XAML compilation.
5. Make SS14Window better thanks to these improvements.
2021-02-14 02:09:37 +01:00
Pieter-Jan Briers
29a39f8e0a Adds LocExtension markup extension for XAML.
Does Loc.GetString().
2021-02-13 15:13:05 +01:00
Pieter-Jan Briers
2d72a2bdb5 Server timing improvements.
Add helpers.
Fix desynchronized NetTime.
2021-02-13 11:42:12 +01:00
Pieter-Jan Briers
91da635631 Fix Robust.Shared.Interfaces namespace in ScriptInstanceShared 2021-02-13 11:42:12 +01:00
chairbender
68ab3d504a Various fixes to support new chatbox (#1547)
* #272 no arrow, actually change id on channel changer

* #272 ability to apply style class to child

* #272 try methods for selecting items in OptionButton.cs

* #272 allow escaping right angle bracket in formatted message

* #272 ability to detect when local player is set / unset

* #272 make RemoveModal public since PushModal is as well, so modals can be removed on-demand if needed rather than relying on a click elsewhere

* #272 revert
2021-02-12 18:20:29 -08:00
Pieter-Jan Briers
5187040a64 Remove unsafe code from GrowableStack 2021-02-13 00:47:05 +01:00
DrSmugleaf
e0c63e7ce6 Add SerializedType attribute to specify the id used in !type tags (#1545)
* Add SerializedType attribute to serialize types without the !type tag

* Fix nulls in tests

* Fix null in tests maybe

* Return to type tags

* Fix imports
2021-02-11 13:50:55 -08:00
Acruid
0ba2272cab Remove all dependencies from LocalizationManager.
Remove IoCManager calls from EntityPrototype.
Add missing using statements preventing EXCEPTION_TOLERANCE from building.
2021-02-11 00:39:12 -08:00
Acruid
2183cd7ca1 Massive Namespace Cleanup (#1544)
* Removed the Interfaces folder.
* All objects inside the GameObjects subfolders are now in the GameObjects namespace.
* Added a Resharper DotSettings file to mark the GameObjects subfolders as not providing namespaces.
* Simplified Robust.client.Graphics namespace.
* Automated remove redundant using statements.
2021-02-10 23:27:19 -08:00
DrSmugleaf
cbf01f0aa5 Fix ComponentChangedSerialized test (#1543) 2021-02-09 21:24:28 +01:00
Pieter-Jan Briers
6973d43006 Network timing synchronization.
Lidgren NetTime.Now is now synchronized to IGameTiming.RealTime.

NetChannel is now a nested class of NetManager.

Add IGameTiming.ServerTime, INetChannel.RemoteTimeOffset, INetChannel.RemoteTime
2021-02-09 14:28:20 +01:00
Pieter-Jan Briers
c5a961d9a0 Even better: use argStr. 2021-02-09 14:28:20 +01:00
Acruid
b4f7d71ee7 Server console can forward commands to a client. 2021-02-09 04:16:15 -08:00
metalgearsloth
cd3684e575 Guard against client appearancecomp changes (#1540)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-09 13:13:05 +01:00
Pieter-Jan Briers
317b8ce965 Fix sudo command mangling quotes. 2021-02-09 12:29:23 +01:00
Pieter-Jan Briers
ff96140afa Fix messed up \n. 2021-02-09 03:17:27 +01:00
Pieter-Jan Briers
bade95f6b7 Fix unit tests 2021-02-09 02:37:27 +01:00
Pieter-Jan Briers
69daaca399 Remove CVar.SECURE and replace auth CVars with env variables. 2021-02-09 01:50:42 +01:00
DrSmugleaf
5af7e60043 Add KeyValuePair YAML serialization (#1538) 2021-02-08 21:49:08 +01:00
DrSmugleaf
ab823dcd12 Add component registration lookup with case insensitive names (#1535) 2021-02-08 18:07:23 +01:00
Paul Ritter
b3976eb8d7 Analyzer Bongaloo 2: The Return (#1512)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-02-08 18:05:27 +01:00
Pieter-Jan Briers
91759cdd3c Harder DynamicTree against NaN.
B2DynamicTree<T> has asserts, DynamicTree<T> handles them gracefully.

NaNs in DynamicTree were causing the internal state to corrupt resulting in the sprite flickering issues.

Fixes https://github.com/space-wizards/space-station-14/issues/2896
2021-02-08 05:03:56 +01:00
Pieter-Jan Briers
b000c3178b FileLogHandler is now internal.
Sandboxing thing.
2021-02-07 23:07:57 +01:00
Vera Aguilera Puerto
63b3ecdd13 Fix SpawnRepeating timer extensions 2021-02-07 17:04:43 +01:00
DrSmugleaf
a183a98f75 Add support for deserializing nullable enum types (#1537) 2021-02-07 14:31:38 +01:00
Acruid
bded7ad228 You can now provide a factory delegate to IoC register calls. 2021-02-06 23:00:08 -08:00
metalgearsloth
75c4f48496 Fix NPCs getting stuck (#1533)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-05 20:38:01 +01:00
Acruid
49fe2d59cf Removes hard-coded color support for writing console shells. Strings with formatting codes can replace this feature.
Added a separate WriteError function to console shell, to mimic writing to stderr.
2021-02-05 01:35:06 -08:00
DrSmugleaf
8a5b7f5146 Add AudioSystem extension methods for the client and server (#1532) 2021-02-05 17:23:36 +11:00
Pieter-Jan Briers
ae4f470e1f Fix duplicate .xaml files. 2021-02-04 15:22:18 +01:00
metalgearsloth
18fcab6f71 Fix loadbp on paused maps (#1531)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-04 23:29:37 +11:00
Acruid
1ae6c32c62 Adds the net_entityreport console command, that displays a network history of entity updates. 2021-02-03 23:19:47 -08:00
Pieter-Jan Briers
cf6925f19b Makes sudo command show output to user. (#1530) 2021-02-03 19:31:32 -08:00
Pieter-Jan Briers
b4c7ffe38a Adds an exec command.
Just like Quake. Man that Carmack guy was onto something.
2021-02-04 03:40:03 +01:00
Pieter-Jan Briers
d5c2f45f14 Fix accidental usage of OpenGL DSA in screenshot code. 2021-02-03 21:10:48 +01:00
Pieter-Jan Briers
dcc88d2d36 Fix KHR_debug detection on OpenGL ES. 2021-02-03 21:10:48 +01:00
metalgearsloth
a274b8dfc2 EntityQuery no longer yields paused by default (#1521)
* Change EntityQuery to not get paused by default

* GetAllComponents

* Fix shell commands

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-04 00:20:31 +11:00
Paul Ritter
f42c1379e0 Revert "Viewport improvements. (#1510)" (#1527)
This reverts commit fc5e3ab69d.
2021-02-03 12:25:12 +01:00
Pieter-Jan Briers
c4fa7e98d4 Fix clients not disconnecting correctly when client is closed. 2021-02-03 00:04:41 +01:00
Vera Aguilera Puerto
8b9dadffb1 MIDI improvements (#1526) 2021-02-02 18:46:24 +01:00
Vera Aguilera Puerto
5e99c6d04d ViewVariables server-side "Add Component" button isn't hidden anymore when searching for components. 2021-02-02 13:28:56 +01:00
Vera Aguilera Puerto
606d232dbb Update ViewVariables to use the new commands API 2021-02-02 13:26:41 +01:00
Vera Aguilera Puerto
df877582a6 You can now add or remove components from the comfort of ViewVariables (#1524) 2021-02-02 12:01:54 +01:00
Acruid
8ffdb090e6 Adds a property on ITransformComponent that prevents the entity from being rotated. Resolves #1479. 2021-02-01 20:27:17 -08:00
Acruid
033d6ffb22 Fixes bug where effects were dying in transit from lag. Resolves #1256. 2021-02-01 19:17:34 -08:00
Acruid
3eb6e067f9 Console Unify (#1513)
* Renamed shared ICommand to IConsoleCommand.

* Lots of refactoring into a shared context.

* Removed ICommonSession from server concmd Execute.

* Added argStr parameter to concmd execute.

* The execute function of client concmds now returns void, use the new shell.RemoteExecuteCommand function to forward commands.

# Conflicts:
#	Robust.Client/Console/Commands/Debug.cs

* Finally move shells and commands into shared.

* Console commands can now be registered directly without a class in a shared context.

* Pulled up ConsoleHost and Console shell into a shared context.

* Pulled up half the functions of ConsoleHost into a shared context.

* Repair rebase damage.

* Make LoadConsoleCommands function not remove any previously registered commands.
2021-02-01 16:40:26 -08:00
Vera Aguilera Puerto
1f64f93ef4 Update nfluidsynth to latest version, 0.3.1 2021-02-01 21:33:22 +01:00
Pieter-Jan Briers
7dd617b0d6 Adds reflection helper methods to script globals. 2021-02-01 19:41:02 +01:00
metalgearsloth
0567b70704 Optimise showbb (#1519)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-01 20:15:50 +11:00
Pieter-Jan Briers
9963e89c14 Sanitize ResourcePath to disallow .. shenigans. 2021-01-31 22:38:40 +01:00
Remie Richards
29e0faed88 Can now animate ITransformComponent.WorldPosition (#1518) 2021-01-30 23:26:01 +01:00
Pieter-Jan Briers
0ce6ff9870 Fix tickrate sync if non-default tickrate saved to client config.
Fixes #1516

Thanks to blue on Discord for helping me diagnose this.
2021-01-30 01:27:42 +01:00
Vera Aguilera Puerto
dbe9a96dfa Reorganizes NumericsHelpers into different files using partial classes. (#1514) 2021-01-29 12:46:27 +01:00
Vera Aguilera Puerto
fc5e3ab69d Viewport improvements. (#1510)
* Remove the main viewport.

* Re-add main viewport in a different place

* Move screen/map translation into ViewportContainer

* Support for viewport resolution

* Fix postfx, add WorldToScreen to Viewport

* Remove useless cast

* Some cleanup.

* Fix incorrect worldBounds when rendering viewports

* nullability

Co-authored-by: 20kdc <asdd2808@gmail.com>
2021-01-29 12:45:04 +01:00
Julian Giebel
ed4974141c Add TryCastValue to CollectionExtensions.cs (#1515)
* Add TryCastValue to CollectionExtensions.cs

* Change TryCastValue to be more generic

* Add notnull constraing for TKey to TryCastValue

Co-authored-by: Julian Giebel <j.giebel@netrocks.info>
2021-01-28 20:45:11 +01:00
Pieter-Jan Briers
3e5efd5ed0 Add AnimatedTextureRect 2021-01-24 23:00:02 +01:00
Pieter-Jan Briers
e1110eadb4 Better unified handling of SpriteSpecifiers
Add more utilities, most notably IRsiStateLike, to make working with SpriteSpecifiers easier. Especially when animated.
2021-01-24 22:59:47 +01:00
Pieter-Jan Briers
06ace83a73 Allow audio playback without grids. 2021-01-24 16:04:23 +01:00
Pieter-Jan Briers
cd01ca924b Fix broken PanelContainer due to previous commit.
God I am tired.
2021-01-24 04:20:51 +01:00
Pieter-Jan Briers
38ad8ce132 Fix UI scaling weirdness with PanelContainer. 2021-01-23 21:51:35 +01:00
20kdc
ee440c2df9 Make the lighting manager much more configurable, including a console lock (#1506) 2021-01-23 21:17:49 +01:00
Pieter-Jan Briers
32f3c863fb Fix UI scaling bugs with ProgressBar 2021-01-23 20:15:45 +01:00
Pieter-Jan Briers
b00e0bef5a Fix UI scaling bug with RichTextLabel 2021-01-23 16:02:31 +01:00
Pieter-Jan Briers
0a09b27918 Fix UI scaling bug with GridContainer 2021-01-23 16:02:23 +01:00
Paul
c9f6a4e32a fixes enum VV 2021-01-21 15:33:42 +01:00
Pieter-Jan Briers
b205a14f69 Exception tolerance for NetManager.OnDisconnect 2021-01-20 21:07:02 +01:00
Pieter-Jan Briers
d5f3292e0a Unregister OnSessionOnPlayerStatusChanged on bound user interfaces.
I am frankly flabbergasted this is only a problem now.
2021-01-20 21:00:24 +01:00
Pieter-Jan Briers
561e4b330e Fix ALL components memory leaking.
:irrational:
2021-01-20 20:45:02 +01:00
Paul
36a5d102ff prevent one error from killing the entire namegenerator from running 2021-01-17 17:17:02 +01:00
Pieter-Jan Briers
b9c39e0953 Fix reconnecting. 2021-01-17 16:08:48 +01:00
Pieter-Jan Briers
ad4c8be132 Add system for preserving Map UIDs across edits. 2021-01-17 15:51:32 +01:00
kira-er
988cbf9a87 VV Enum (#1503) 2021-01-17 01:50:26 +01:00
Acruid
e26512001a Completely removed MsgSetTickRate, the NetConfigurationManager replaces the functionality. This builds on top of the previous commit.
Fixes bug where server was not sending the entire set of replicated cvars.
2021-01-16 15:33:44 -08:00
Pieter-Jan Briers
8e97982f1e Fix net.tickrate not being replicated correctly to clients. 2021-01-16 21:46:10 +01:00
Paul
3ca686298e Fixes ViewVariablesManager using the wrong VVPropEditor for Type in shared not annotated with [NetSerializable] 2021-01-16 20:05:15 +01:00
20kdc
5e914cb13a PointLightComponent: Don't dirty if enabled is being set to what it's already set to. (#1507) 2021-01-16 00:13:55 +11:00
Pieter-Jan Briers
a1bdfca8ba Fix SimplePredictReconcileTest. 2021-01-15 11:03:52 +01:00
20kdc
79deaca409 Polar Coordinates: simplify maths, any-angle occluders are no longer evil (#1504)
Someone please performance-test this, but I think the fragment shader code simplifications speak for themselves.

Radrark found the "line in polar coordinates" equation I needed and a diagram that explained the variables.

That equation was essentially the missing piece to the whole thing.
2021-01-14 13:44:25 +01:00
20kdc
2eeb21431b Fix FileDialogManager not doing DLL mapping properly in sandbox, and FileDialogManager hard crash on multiple dialogs (#1505) 2021-01-14 13:43:39 +01:00
chairbender
c4062bcae9 #1449 new ControlFocusExited override for allowing controls to know (#1467)
when they lost control focus, separate from keyboard focus
2021-01-13 23:18:45 +01:00
Acruid
cd3a85ea04 Replicated CVars (#1489) 2021-01-13 10:02:08 +01:00
Pieter-Jan Briers
d15b5c7f22 Fix compiler warnings. 2021-01-13 03:10:51 +01:00
Leo
18bbe2271d Adds extension method to read and write colors on NetMessages (#1500) 2021-01-13 01:12:55 +01:00
Pieter-Jan Briers
ee2b7a3a66 Adds gcm function to ScriptGlobalsShared 2021-01-12 21:17:35 +01:00
Pieter-Jan Briers
ca36671131 Fix nullable error in RadioOptions 2021-01-12 21:17:26 +01:00
Pieter-Jan Briers
604a1a6960 Disable CodeQL crap since it STILL doesn't do .NET 5 and I'm sick of the errors. 2021-01-12 17:20:11 +01:00
Pieter-Jan Briers
2898f5396f Account for windows time period latency in Lidgren.
1. Set timeBeginPeriod(3) on the server to reduce scheduler latency in the lidgren thread.
2. Add 16ms of guaranteed lag bias to client prediction calculations to account for scheduler latency.

Both of these changes are to account for how the windows scheduler seems to handle time periods in related to socket polls. See this Discord conversation for why, details down below as well: https://discord.com/channels/310555209753690112/770682801607278632/798309250291204107

Basically Windows has this thing called time periods which determines the precision of sleep operations and such. By default it's like 16ms so a sleep will only be accurate to within 16ms.

Problem: Lidgren polls the socket with a timeout of 1ms.

The way Windows seems to handle this is that:
1. if a message comes into the socket, the poll immediately ends and Lidgren can handle it.
2. If nothing comes in, it takes the whole 16ms time period to actually process stuff.

Oh yeah, and Lidgren's thread needs to keep pumping at a steady rate or else it *won't flush its send queue*. On Windows it seems to normally pump at 65/125 Hz. On Linux it goes like 950 Hz as intended.

Now, the worst part is that (1) causes Lidgren's latency calculation to always read 0 (over localhost) instead of the 30~ms it SHOULD BE (assuming client and server localhost).

That 30ms of unaccounted delay worst caseis enough to cause prediction undershoot and have messages arrive too late. Yikes.

So, to fix this...

On the server we just decrease the tick period and call it a day. Screw your battery life players don't have local servers running anyways.

On the client we bias the prediction calculations to account for this "unmeasurable" lag.

Of course, all this can be configured via CVars.
2021-01-12 02:43:15 +01:00
bgare89
39541639c5 Add RadioOptions.cs (#1484)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
2021-01-12 01:45:15 +01:00
metalgearsloth
50981ad1a1 Layered PlacementManager (#1403)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-11 22:42:54 +11:00
Pieter-Jan Briers
0cbfbeffae Revert "Analyzer to check if interfacemethods are explicitly marked as such" (#1499)
This reverts commit e603153016.
2021-01-11 12:26:23 +01:00
Paul Ritter
e603153016 Analyzer to check if interfacemethods are explicitly marked as such (#1477)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2021-01-11 12:14:26 +01:00
Pieter-Jan Briers
e7c417ca0c Remove a couple MiB of memory usage. 2021-01-11 10:58:42 +01:00
Pieter-Jan Briers
a3989f28eb Re-order exception handler in StatusHost to avoid blowing up in some cases ??? 2021-01-11 10:24:29 +01:00
Pieter-Jan Briers
38ace3c348 Fix exception with trying to place entities at... NaN?
This is still a bug but it should not cause an exception on the server
2021-01-11 10:24:29 +01:00
Ygg01
0e00170f45 Make RSI directions default to 1. (#1495)
Add some helper methods, made an `example.rsi` for testing.

Closes #1463
2021-01-11 18:12:34 +11:00
Pieter-Jan Briers
261ee96cad Make client connect 1 second faster.
Whoops.
2021-01-11 02:39:35 +01:00
Pieter-Jan Briers
2c851885db Fix ItemList not working correctly with scaling. 2021-01-11 02:06:25 +01:00
Pieter-Jan Briers
849be86455 Add launchauth command to bootstrap login tokens for connecting to live servers. 2021-01-10 23:55:01 +01:00
Pieter-Jan Briers
ffd5c120be Add PreserveBaseOverridesAttribute to sandbox whitelist.
Used by covariant returns.
2021-01-10 22:03:18 +01:00
Vera Aguilera Puerto
76b15dda70 Client-side addcompc/rmcompc (#1497) 2021-01-10 20:09:14 +01:00
Vera Aguilera Puerto
0bf7f519ad Adds client-side setinputcontext command (#1498) 2021-01-10 20:08:44 +01:00
Vera Aguilera Puerto
f97f325a36 Fixes sprite scale not being taken into account. (#1496)
* Fixes sprite scale not being taken into account.
- Only apply scale if length of scale vector not close or equal to 1.

* I blame Remie

* Fix vector maths
I should spend more time studying maths instead of contributing, to be fair.

* Remie no please nO
2021-01-10 19:53:04 +01:00
metalgearsloth
24315fa787 Avoid unnecessary EntMapIdChangedMessages (#1493)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-10 12:46:59 +11:00
Ygg01
792179657b Fix space in dotnet breaking windows builds (#1490)
Who would win?
Thirty developers
-OR-
One sneaky ` ` boi?

On windows default path to dotnet are `C:\Program Files`. Without quoting the
the command if it contains a space, it's going to break Windows builds that
install in `C:\Program Files`.
2021-01-08 13:53:42 +01:00
Paul
9b92bcf911 intermediate fix to garantuee people with dotnet in path to launch commpilerobustxaml 2021-01-05 12:15:03 +01:00
metalgearsloth
86e34ea27b Fix enum caching (#1485)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-05 16:17:20 +11:00
Clyybber
62cf778958 Fix build when dotnet is not in the PATH (#1483) 2021-01-04 20:25:43 +01:00
py01
5d667e44c3 Replaces AnchoredChanged C# event with a ComponentMessage (#1482)
Co-authored-by: py01 <pyronetics01@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-01-04 10:16:05 +01:00
metalgearsloth
6d84b8741c Cache enum references (#1480)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-01-03 03:45:02 +01:00
DrSmugleaf
d08ca59b75 Make RobustUnitTest register content cvars and set _isServer (#1481) 2021-01-03 03:44:12 +01:00
Pieter-Jan Briers
f06b046c1c Fix Content-Type not being set for status API. 2021-01-03 03:42:21 +01:00
Vera Aguilera Puerto
bb412a6906 Entity Timer SpawnTimer throws if entity is deleted. 2021-01-01 15:45:13 +01:00
Radrark
1baee3004c Adds new keybind property: AllowSubCombs (#1473)
Co-authored-by: Radrark <null>
2020-12-29 15:59:34 +01:00
Pieter-Jan Briers
f18068c13a Update NetSerializer submodule to improve build times 2020-12-29 15:59:13 +01:00
Pieter-Jan Briers
0ba00a1845 Gcf command to mess with LOH compaction. 2020-12-29 14:10:15 +01:00
Pieter-Jan Briers
28caf0d74c Reduce allocations 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
ecbb32b70b Clean up various cases of failing to dispose file streams. 2020-12-29 03:58:16 +01:00
Pieter-Jan Briers
8e2a9cc597 Font atlasses are now dynamic and can render all glyphs in the font file. 2020-12-29 03:58:16 +01:00
Vera Aguilera Puerto
a7eb8201c9 Fix MIDI soundfont load error on non-rooted paths. 2020-12-26 22:05:17 +01:00
Pieter-Jan Briers
1f95fe6782 Fix XamlIL problems when publishing 2020-12-25 18:34:19 +01:00
DrSmugleaf
07c1f9e1af Replace MaybeNullWhen(false) with NotNullWhen(true) in AppearanceComponent (#1461) 2020-12-25 15:17:54 +01:00
Vera Aguilera Puerto
826dce6659 Fix custom MIDI soundfont loading when mounting content from zip
Fixes #1466
2020-12-24 03:54:06 +01:00
Vera Aguilera Puerto
cdf714f3ba Fix stereo ogg audio not playing correctly.
Only half of the samples were being read.
2020-12-23 16:21:42 +01:00
Pieter-Jan Briers
671ca7959c Throw debug info if the RichTextEntry assert fails. 2020-12-23 15:12:47 +01:00
Pieter-Jan Briers
b7a1345d3a XAML compilation improvements.
Prevent double XAML-ifying causing corrupt dlls.

Use MSBuild dependencies to reduce unecessary xamlil builds.
2020-12-23 12:01:35 +01:00
Pieter-Jan Briers
835b6ebdba Probably fix build forgetting that nuget exists. 2020-12-21 12:14:28 +01:00
Pieter-Jan Briers
0ecabd6553 Fix XamlIL locking build. 2020-12-21 12:13:45 +01:00
Pieter-Jan Briers
feaa69f825 Fix build of injector. 2020-12-21 04:05:34 +01:00
Pieter-Jan Briers
857904a3d9 Update dependencies of name generator. 2020-12-21 04:05:25 +01:00
Pieter-Jan Briers
0b37418477 Fix injectors UsingTask. 2020-12-21 03:31:11 +01:00
Pieter-Jan Briers
f234ecb2c3 Make Robust.Client.Injectors NS2.0
So that it works out of the box with Framework MSBuild.
2020-12-21 03:16:13 +01:00
Pieter-Jan Briers
b449959865 Clean up bad project reference in Robust.Server 2020-12-21 03:15:45 +01:00
Pieter-Jan Briers
8f870403d2 Managed implementation of HttpListener. (#1460) 2020-12-21 02:51:04 +01:00
Paul Ritter
d94f702601 Xaml UI (#1446)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-12-20 23:52:36 +01:00
DrSmugleaf
e78ab8f922 Add YamlObjectSerializer.NodeToType with generic argument (#1456) 2020-12-20 20:46:56 +01:00
20kdc
6972000293 Make the "softness" of soft shadows adjustible per-light. (#1454)
Note: Thanks to the nature of YAML properties in RobustToolbox, this commit is only an API blocker if the Softness property is directly manipulated from code, which is unlikely.
2020-12-19 21:44:47 +01:00
DrSmugleaf
58560f589f Defer MoveEvent out of TransformComponent.HandleComponentState (#1453)
* Defer MoveEvent out of TransformComponent.HandleComponentState

* Imports

* Make the update loop more readable and call ToArray

* Fix tests

* Fix tests HALLELUJAH
2020-12-19 13:09:16 +01:00
Pieter-Jan Briers
6e931ac175 Fix some CVars not saving. 2020-12-19 02:31:46 +01:00
Pieter-Jan Briers
a7eb5e8115 Use nvidia GPU on optimus laptops.
With an undocumented crappy hack, of course.
2020-12-19 02:25:10 +01:00
metalgearsloth
712e4acc66 Cache TryLooseGetType (#1448)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-12-19 01:42:51 +01:00
Pieter-Jan Briers
fdcfdffc0b Provide fallback for /status API if content does not override it. 2020-12-19 00:43:46 +01:00
Pieter-Jan Briers
74eb8e3e8d Allow build.json contents to be overriden by --cvar. 2020-12-17 17:13:07 +01:00
Pieter-Jan Briers
ae4c764e4f Whitelist System.Guid for sandbox. 2020-12-17 16:37:20 +01:00
Pieter-Jan Briers
7ef2cec121 Fix names parsed from build.json 2020-12-17 15:28:01 +01:00
Pieter-Jan Briers
40bff81017 Fix nullable warning. 2020-12-17 00:58:26 +01:00
Pieter-Jan Briers
f7c28992f8 Disable string map caching to hopefully fix connect. 2020-12-17 00:48:15 +01:00
Pieter-Jan Briers
920ae58019 Fix LoaderApiLoader.FindFiles() 2020-12-17 00:33:39 +01:00
Pieter-Jan Briers
5bb21e07de Engine versioning. 2020-12-16 23:53:51 +01:00
Pieter-Jan Briers
78ceaa50d5 Update Lidgren submodule. 2020-12-16 18:18:40 +01:00
Pieter-Jan Briers
7473b6dae1 Optimize assembly type checking.
It's now parallelized which cuts off ~200ms on its own for me.
Config is now shared between multiple loads which saves a lot as well.

All in all, pretty good.
2020-12-14 16:34:33 +01:00
Pieter-Jan Briers
c335170fc1 Add non-generic System.Nullable to sandbox whitelist. 2020-12-13 21:33:22 +01:00
Pieter-Jan Briers
13e9fe12ce Further fixes to loader exe.
Fix ordering of loads.
Fix loads.
2020-12-13 16:12:32 +01:00
Pieter-Jan Briers
7ef2fd46da Hail NuGet 2020-12-13 01:14:50 +01:00
Pieter-Jan Briers
f048209bf5 FUCK BOMs 2020-12-13 01:10:21 +01:00
chairbender
1bf9e2e87a Multiselect option button, tooltip delay (Action Hotbar Support) (#1435) 2020-12-13 01:01:00 +01:00
Pieter-Jan Briers
fd4f45e670 Use NuGet packages for engine natives.
Fixes #1434

This means that adding support for new architectures (e.g. ARM) is MUCH easier.

It removes  download_natives.py which simplifies the build process.

It's also way less painful to maintain.
2020-12-13 00:46:23 +01:00
Pieter-Jan Briers
f15c1c7a95 Allow engine to be loaded from a zip file itself. 2020-12-12 11:12:37 +01:00
DrSmugleaf
50f0a4389e Fix the server not setting IsConnected to false for disconnecting clients in integration tests (#1442) 2020-12-12 00:53:10 +01:00
komunre
cab6277b2d FixClipping() now check if entity is deleted (bug fix) (#1441)
* check for deletion in CanMove()

* Added deleted check in FixCollide

* Removed Owner.Deleted check from CanMove()
2020-12-12 04:37:32 +11:00
Pieter-Jan Briers
797fa9cffa Fix server failing to start due to non-int LogLevel enum. 2020-12-10 15:22:29 +01:00
20kdc
a20245d623 Fix grid bounds going out of sync with chunk collision regeneration (#1440)
Fixes #1439
2020-12-10 14:38:03 +01:00
Pieter-Jan Briers
04cc1f616d Permissive markup parsing. 2020-12-09 13:08:06 +01:00
Pieter-Jan Briers
8cd6f63f17 Make FormattedMessage tags records, clean up tests. 2020-12-09 13:08:06 +01:00
Ygg01
ad8b0b3c83 Add bytes or sbytes to enum where available (#1430)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-12-08 12:46:30 +01:00
Paul Ritter
f157cdce02 Rotatable bounding boxes (#1360)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-12-07 17:01:57 +01:00
DrSmugleaf
2504a42f88 Fix typo in exception message 2020-12-07 15:21:38 +01:00
Pieter-Jan Briers
d0191e063a Fix all cases of member references to array (not vector) types.
Yeah generics aren't the only one since you can do [,][,].
2020-12-07 00:12:05 +01:00
Pieter-Jan Briers
b96bcbd357 Fix member ref handling of non-vector generic arrays in type checker. 2020-12-05 23:13:04 +01:00
Pieter-Jan Briers
ae14031377 Fix version parsing. 2020-12-05 18:02:12 +01:00
Pieter-Jan Briers
1d19007012 Missing parentheses... 2020-12-05 17:42:32 +01:00
Pieter-Jan Briers
f5390f21c3 Change client publish to be on tag push. 2020-12-05 17:36:48 +01:00
Pieter-Jan Briers
0fea0fba08 Third try at client publish 2020-12-05 17:04:24 +01:00
Pieter-Jan Briers
7517f0d868 Second try at client publish 2020-12-05 16:54:06 +01:00
Pieter-Jan Briers
3351b13b26 workflow to publish engine versions 2020-12-05 16:50:17 +01:00
Pieter-Jan Briers
242f187263 Stuff to export standalone builds of Robust.Client. 2020-12-05 01:50:33 +01:00
Pieter-Jan Briers
8357940ef6 Try to fix integration test failures. 2020-12-04 13:04:01 +01:00
DrSmugleaf
93dca3a914 Add EnsureComponentWarn methods (#1431) 2020-12-04 12:53:02 +01:00
Pieter-Jan Briers
4c72103a97 Do not load SECURE cvars from config file.
To avoid funny business by content.
2020-12-04 11:27:41 +01:00
Pieter-Jan Briers
6d78d05520 Do not write unmodified cvars to config file. 2020-12-04 11:23:15 +01:00
Pieter-Jan Briers
953120aa76 Move various config manager APIs to internal. 2020-12-04 11:15:09 +01:00
Pieter-Jan Briers
6275768547 Change client user data dir to Space Station 14/data.
Because, you know, before content could access the engine installation directory.
2020-12-04 11:08:44 +01:00
John Ginnane
6323348a04 Fixed handling keybinds.yml with no binds (#1433) 2020-12-04 11:08:32 +01:00
Pieter-Jan Briers
548735ac3d Clean up engine cvars file.
Add separating comments.
Remove unused CVars.
Add CLIENTONLY or SERVERONLY where applicable.
2020-12-04 10:59:45 +01:00
Pieter-Jan Briers
a4206882f2 Make error on duplicate loading assembly names more clear.
This is extremely inconsequential but I ran into this because I made a mess of my bin folder testing zip mounting SO...
2020-12-04 00:42:28 +01:00
Pieter-Jan Briers
97ea530312 Fix some IoC thread exceptions in HTTP handlers. 2020-12-04 00:15:08 +01:00
Pieter-Jan Briers
ede4962751 Allow specifying resource mount parameters via command line.
Necessary for engine versioning.
2020-12-04 00:15:08 +01:00
Manel Navola
b8b69817ec Added master volume configuration and set master volume method (#1427)
Co-authored-by: Manel Navola <ManelNavola@users.noreply.github.com>
2020-12-03 17:34:13 +01:00
Saphire Lattice
9f07fc4e8a Change connection's time to be UTC, and improve NetUserId to implicitly convert from Guid (#1428) 2020-12-03 15:12:46 +01:00
Vera Aguilera Puerto
5a01d65c68 Container helper to remove and delete all entities in a container. 2020-12-03 11:33:36 +01:00
Vera Aguilera Puerto
e4bccaa6ce Helper to empty a container. 2020-12-02 19:06:31 +01:00
Vera Aguilera Puerto
f380238158 Helpers to remove entities from the containers they're in, if any. 2020-12-02 17:35:53 +01:00
metalgearsloth
72f01cf416 Fix grid-tile lookups for space (#1429)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-30 12:54:29 +01:00
Pieter-Jan Briers
6296171b63 Move some shared engine properties to a new msbuild file. 2020-11-28 18:05:16 +01:00
Pieter-Jan Briers
1508589a2b Fix compiler warnings. 2020-11-28 17:50:28 +01:00
Pieter-Jan Briers
503f72635f Well you certainly tried, GitHub 2020-11-28 17:36:51 +01:00
Pieter-Jan Briers
b8f81789a3 Set up CodeQL since Cyberboss mentioned it.
#333
2020-11-28 17:33:23 +01:00
Pieter-Jan Briers
86d4fafd30 More GC stats. 2020-11-28 15:36:45 +01:00
Pieter-Jan Briers
1d26adf746 Stuff related to IResourceManager.TryGetDiskFilePath.
Makes it not a "temporary todo remove" API since it has merits in e.g. assembly loading performance (.NET can mmap the assembly if it has a disk path which is better).

Removed duplicated IResourceManagerInternal APIs in IResourceCache.
2020-11-28 14:59:27 +01:00
Pieter-Jan Briers
356e99df34 Allow C# 9 records and init-only properties by sandboxing.
The System.Runtime.CompilerServices.IsExternalInit type needed to be added since it is used as a modreq.
2020-11-28 02:34:22 +01:00
Pieter-Jan Briers
ef2ec40e35 Add System.Convert to sandbox whitelist.
Only the Base64 and hex string methods. The rest are all stupid and should not be used anyways.
2020-11-28 02:16:39 +01:00
Pieter-Jan Briers
488c793886 Make AssemblyTypeChecker.Types use records, add whitelist dumper command. 2020-11-28 02:16:38 +01:00
Ygg01
f28d1cb5e0 Add windows-latest to test targets (#1425)
Similar to https://github.com/space-wizards/space-station-14/pull/2634
2020-11-27 20:15:00 +01:00
Pieter-Jan Briers
247ca0c911 Fix C# interactive when modloader is using load contexts.
This fixes it on prod.
2020-11-27 16:56:09 +01:00
Pieter-Jan Briers
08f9aaa8a8 Fix lsasm crashing clyde due to huge message. 2020-11-27 16:39:30 +01:00
Pieter-Jan Briers
2225d23d09 Properly tell client if they can't connect due to "expired" RSA key. 2020-11-27 01:10:10 +01:00
Pieter-Jan Briers
2b39c05472 Return of the HttpListener. (#1423)
Microsoft isn't supporting NuGet-components ASP.NET Core ever since 3.x so using Kestrel is out.

New implementation is 100% thread pool compared to the old one which was a single specific thread.
2020-11-26 23:57:52 +01:00
Pieter-Jan Briers
a41f64f30e sandboxing (#1408) 2020-11-26 23:37:31 +01:00
Ygg01
906db8eb29 Fix Layer copy constructor (#1422)
- Inert flag wasn't propagated properly.
2020-11-26 23:11:17 +01:00
Pieter-Jan Briers
4c0414087e Fix doc error in CVar enum. 2020-11-26 18:02:01 +01:00
Pieter-Jan Briers
300f6861f7 Cut down half of map load time by caching ResolveConcreteType in serializer. 2020-11-26 15:30:18 +01:00
Pieter-Jan Briers
124b447428 Update NuGet packages.
Most notably YamlDotNet which has performance improvements for large files such as our map files.
2020-11-26 02:19:11 +01:00
DrSmugleaf
3ad65ca63f Add searching by component name to View Variables (#1417)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-11-26 02:01:27 +01:00
Pieter-Jan Briers
3767a7d285 Make [UI]Box2[i] unions with their primary corners as fields.
This uses .NET 5's new Unsafe.SkipInit() function and a lot of FieldOffset.

The result of this is that you can now take a `ref` to the primary corners of the boxes, as well as better codegen in some cases.
2020-11-26 02:00:05 +01:00
Pieter-Jan Briers
bf197ce04b Update lidgren and netserializer submodules 2020-11-26 01:19:36 +01:00
Pieter-Jan Briers
32de7b2709 Remove allocations from prometheus system timing. 2020-11-26 01:13:26 +01:00
Pieter-Jan Briers
c28761d5c0 Fix setting cvars with overrides. 2020-11-26 01:11:36 +01:00
DrSmugleaf
b8e5b47e7a Use 'new' expression in places where the type is evident for the engine (#1415)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-11-26 00:16:55 +01:00
20kdc
e82a83223f Cleanup: Fix grid lookups performed just to get map IDs (#1421)
"All of the failures have to fuel success" I don't think applies to pointless exceptions
2020-11-26 00:08:55 +01:00
Víctor Aguilera Puerto
26d1a04bbf Fix missing returns on certain AdvSimd paths causing incorrect results. 2020-11-25 13:31:49 +01:00
Víctor Aguilera Puerto
8572bd0d7f Fix DivideAvx test not being ignored 2020-11-25 11:54:10 +01:00
Víctor Aguilera Puerto
088b2da90a Fix AdvSimd Min for NumericsHelpers 2020-11-25 11:20:54 +01:00
Víctor Aguilera Puerto
6b780c55fd Numerics Helpers: SIMD accelerated array math methods (#1380)
* Numerics helpers

* Comments

* Reuse naive methods for remainders.

* Do naive operation if array length is under 4.

* NumericsHelpers takes in Span, can store elsewhere

* Make some spans read-only

* Enabled static property to disable/enable hardware accelerated paths.

* AVX support.

* welp

* .

* environment variable to disable simd

* Adds ARM support (AdvSimd)

* Fix AVX horizontal sum

* Add unit tests

* NET 5.0 moment

* RemoteExecutor moment

* Add nuget.config to the UnitTesting project only

* Add "ROBUST" prefix to env vars

* Better naming for array length utils

* Revert "Add nuget.config to the UnitTesting project only"

This reverts commit 1d474ff33d.

* Ignore ARM tests, remove #if NET5_0
2020-11-25 10:47:38 +01:00
DrSmugleaf
0114538915 Add TryGet methods for component registrations (#1409) 2020-11-25 01:12:05 +01:00
DrSmugleaf
97bbc5d282 Allow multiline ifs if their body is not multiline itself for the engine (#1416) 2020-11-25 01:11:38 +01:00
DrSmugleaf
60623348d2 Update LangVersion to 9 for all Robust projects (#1414) 2020-11-24 01:36:17 +01:00
Paul Ritter
5f940fdec6 Removes some unused variables (#1420)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2020-11-24 00:51:35 +01:00
Pieter-Jan Briers
2ca5d30e9d C# 9.
Insert glasses joke here.
2020-11-24 00:50:38 +01:00
Pieter-Jan Briers
48014cc2e6 Actually clean up netpeers apparently lol. 2020-11-24 00:49:19 +01:00
Pieter-Jan Briers
2944154bab Fix string serializer crash when using different cultures. 2020-11-21 12:08:45 +01:00
DrSmugleaf
cace2eb88c Update Color.DarkSeaGreen to match .NET 5's (#1412)
* Update Color.DarkSeaGreen to match .NET 5's

* Update doc
2020-11-20 13:56:24 +01:00
DrSmugleaf
37ec9c8635 Update test-content.yml to also use dotnet-version 5.0.100 (#1413) 2020-11-20 13:53:40 +01:00
DrSmugleaf
9ce2e3d451 Update build-test.yml dotnet-version to 5.0.100 (#1411) 2020-11-20 13:15:10 +01:00
Pieter-Jan Briers
add186ea8b .NET 5.
I'll fix the fire in the morning.
2020-11-19 03:54:05 +01:00
Pieter-Jan Briers
0e946ee7a1 Optimize allocations in PVS ExcludeInvisible. 2020-11-19 03:50:21 +01:00
Paul Ritter
a37ac16fa3 EntityPrototypeIcon SpriteSpecifier (#1401)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2020-11-16 01:52:19 +01:00
DrSmugleaf
0eea24326e Add SharedAppearanceComponent as a component reference (#1406) 2020-11-16 01:51:49 +01:00
metalgearsloth
04dba5c45d Fix IconComponent textures (#1402)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-14 01:42:49 +11:00
Pieter-Jan Briers
f5c28cdb0d Fix GridContainer for real. 2020-11-13 02:42:46 +01:00
Pieter-Jan Briers
69fe81ef20 ConGroups are gone. Long live admin flags in content. (#1371) 2020-11-13 01:10:30 +01:00
DrSmugleaf
9963d01a27 Allow multiple module testing callbacks (#1367) 2020-11-13 01:06:10 +01:00
metalgearsloth
09020fea17 Don't initialize dummyicon appearance (#1391)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-13 01:04:05 +01:00
Paul Ritter
ef622f7dde spritecomp will ignore state/texture attribute when layers are defined (#1399)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
2020-11-13 01:03:47 +01:00
metalgearsloth
60d8266339 Fix timer enumeration (#1390)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-13 00:47:49 +01:00
Pieter-Jan Briers
5dc15b90c6 Optimize some allocations. 2020-11-11 01:30:09 +01:00
Pieter-Jan Briers
6b3beb3808 Forgot to enable unsafe on Robust.Server 2020-11-11 01:27:31 +01:00
Pieter-Jan Briers
49d2ef96b9 Use [SkipLocalsInit] 2020-11-11 01:19:55 +01:00
Pieter-Jan Briers
539b78cfb1 Clear stackallocs in GridContainer.
For SkipLocalsInit
2020-11-11 01:18:36 +01:00
Pieter-Jan Briers
362b7804d9 Fix issues with .NET 5. 2020-11-11 00:46:35 +01:00
Pieter-Jan Briers
8ef13e6918 Update Lidgren and NetSerializer submodules. 2020-11-11 00:43:58 +01:00
metalgearsloth
bb2867ad74 Fix occluder tree crash (#1397)
* Fix occluder tree crash

* TryGet

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-10 20:06:34 +11:00
chairbender
ee381804ec New GridContainer capabilities and customizable tooltips (#1395)
* #272 avoid mouse overlapping tooltip when near edges,
change tooltip colors to match mockups

* #272 WIP customizable tooltips, old approach currently working still

* #272 WIP customizable tooltips, old approach currently working still

* #272 ensure tooltips go away when disposing control

* #272 implement row-oriented GridContainer

* #272 generalize GridContainer to support
rows or cols

* #272 improve readability in new GridContainer
logic

* #272 GridContainer can expand in opposite
direction

* #272 GridContainer can expand in opposite
direction

* #272 GridContainer can expand in opposite
direction, fix test

* #272 add GridContainer capability to
limit by size rather than count

* #272 add some clarifications about ui scale and vp / rp

* #272 don't spam showtooltip
event, calculate tooltip
positioning using combined
minimum size
2020-11-10 15:21:32 +11:00
DTanxxx
791fcfd65e Updated ContainerHelpers to use new extensions (#1396)
Co-authored-by: David Tan <>
2020-11-09 09:22:31 +01:00
DrSmugleaf
d5982b3ea2 Make ContainerHelpers methods extensions (#1389) 2020-11-07 11:23:12 +11:00
metalgearsloth
df90397cbe Minor physics optimisation (#1351)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-06 23:39:56 +11:00
Víctor Aguilera Puerto
fd93fcb89c EyeComponent improvements (#1384)
* EyeComponent improvements

* Use EqualsApprox where appropiate.

* Update Robust.Client/GameObjects/Components/Eye/EyeComponent.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2020-11-06 19:29:44 +11:00
metalgearsloth
60400418a5 Alphabetise cvars (#1379)
* Alphabetise cvars

* Update Robust.Client/Console/Commands/ConfigurationCommands.cs

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Víctor Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-11-05 17:52:40 +01:00
Víctor Aguilera Puerto
04277feba6 AlignWithClosestGridTile extension for EntityCoordinates (#1386)
* AlignWithClosestGridTile extension for EntityCoordinates
- Fixes component exception when adding a timer component to a deleted entity.

* Address review

* actually...
2020-11-05 17:48:57 +01:00
metalgearsloth
5a3ac6a807 Dummy icon tryget (#1381)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-04 16:04:13 +01:00
metalgearsloth
7dd070856f Fix de-parenting contained entities (#1382)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-04 11:41:09 +01:00
metalgearsloth
178e2cbd76 Make icons great again (#1349)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-04 02:33:15 +01:00
metalgearsloth
04a2a832ac Make pause name less bad (#1376)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-04 01:40:00 +01:00
Víctor Aguilera Puerto
245c0f578d Adds grid ID to debug coords panel. 2020-11-03 19:36:30 +01:00
metalgearsloth
71033099e4 Fix initialized entity physics (#1377)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-03 21:45:53 +11:00
Víctor Aguilera Puerto
96b5779078 Improve math helper for next multiple. 2020-11-02 18:14:09 +01:00
Víctor Aguilera Puerto
6299302025 Adds math helper to get the next closest multiple of a number given a value. (#1378) 2020-11-02 17:04:10 +01:00
metalgearsloth
ab4be1a3c3 (Attempt to) draw world overlays inbetween entities (#1335)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-01 23:25:50 +01:00
metalgearsloth
ad3932b213 Guards for physics state updates (#1373)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-01 23:25:17 +01:00
Paul Ritter
f1552aa34d adds onadd & onremove methods to componentdependencies (#1336) 2020-11-01 23:24:35 +01:00
metalgearsloth
3c428a17a8 Fix collision inaccuracy (#1375)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-11-01 19:08:33 +01:00
metalgearsloth
910a33da53 Fix collision crash (#1370)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-31 12:15:44 +11:00
metalgearsloth
2f21a2551e Fix grid parenting (#1347)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-30 01:02:14 +01:00
DrSmugleaf
abe7d679a3 Add timer component (#1358) 2020-10-30 01:01:27 +01:00
metalgearsloth
deeda5cfa5 Grid-tree occluders (#1362)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-30 00:59:52 +01:00
DrSmugleaf
2296699651 Add shared and server eye components (#1356) 2020-10-30 00:55:56 +01:00
Peter Wedder
a6a98fb6b4 Add program change event field to IMidiRenderer (#1369) 2020-10-30 00:51:32 +01:00
zionnBE
2f79fddec7 Add teleport to player console command (#1366)
* Add teleport to player command

* Clearer description

* Simplify teleport

Co-authored-by: zionnBE <zionn@tfwno.gf>
2020-10-29 15:09:23 +01:00
metalgearsloth
6e91150e76 Virtual controller fix (#1363)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-29 13:07:45 +01:00
metalgearsloth
1e723eae92 Make transformstate actuall check equals (#1361)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-29 13:05:38 +01:00
metalgearsloth
ac5ad96117 Make lockers pushable again (#1353)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-29 20:38:12 +11:00
DrSmugleaf
dc62ac6560 Fix map deserialized entities not being included in OccluderSystem (#1357)
* Fix map deserialized entities not being included in OccluderSystem

* Revert "Fix map deserialized entities not being included in OccluderSystem"

This reverts commit 0af8b50231.

* Make it do it in occluder startup instead
2020-10-29 20:34:30 +11:00
Víctor Aguilera Puerto
214ba440dc Float spinbox (#1354)
corner styles

Co-authored-by: a.rudenko <creadth@gmail.com>
2020-10-27 20:01:04 +01:00
metalgearsloth
4fd1084946 Rotation rounding (#1352)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-27 00:34:50 +01:00
metalgearsloth
4bc53ebfe8 Fix (some) physics stuttering (#1327)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-25 15:37:03 +01:00
Pieter-Jan Briers
1f423c99e6 Configure default auth server. 2020-10-24 15:56:58 +02:00
ShadowCommander
3781844d77 Fix TextReleaseFocus keybind for console not handling args (#1346)
Clean up OnKeyBindDown of DebugConsole
2020-10-24 15:51:44 +02:00
20kdc
4f6a4c8a28 Lighting: Polar Coordinates fix: Sparkle-Be-Gone (#1345) 2020-10-24 15:51:17 +02:00
DrSmugleaf
6bbc4b01e9 Change cvar usages to use CVarDef and define them in CVars (#1330)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-10-24 15:40:06 +02:00
Pieter-Jan Briers
2c999faea5 Don't run updates for entity systems without the methods overriden. 2020-10-22 11:09:53 +02:00
Pieter-Jan Briers
a67cbd9cb9 Fix the last of the compiler warnings. 2020-10-22 10:26:13 +02:00
Víctor Aguilera Puerto
6a9cb790c0 Remove debug assert that doesn't apply anymore...
...after the removal of default grids.
2020-10-21 16:52:05 +02:00
Víctor Aguilera Puerto
0ef57a651e Fix loc command to get map and grid IDs from coordinates. 2020-10-21 16:12:24 +02:00
Víctor Aguilera Puerto
4b709ebb44 Fix SnapGridComponent for entities without grid. 2020-10-21 16:04:58 +02:00
Pieter-Jan Briers
972fd951f6 Fix IsWeightless for entities without grid. 2020-10-21 15:38:37 +02:00
Pieter-Jan Briers
c4e5161199 Fix compiler warnings in unit tests. 2020-10-21 15:14:49 +02:00
Víctor Aguilera Puerto
47593307b6 Remove default grids (#1322)
* Remove default grids

* Fix test. Invalid grids don't "exist" anymore in map manager.

* Fix crashes

* Fix placement modes.

* Remove warning.
2020-10-21 15:12:02 +02:00
RedlineTriad
84e60421e0 Remove leftover Travis files and clean up README.md (#1342) 2020-10-21 14:56:58 +02:00
metalgearsloth
4c698311e8 Physics speed limit (#1344)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-21 10:25:26 +02:00
metalgearsloth
9cc3c2ccd5 Don't wake immovable objects (#1343)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-21 10:24:42 +02:00
Pieter-Jan Briers
62b60fc426 Add GetOffset() helper to SnapGridComponent. 2020-10-20 12:04:46 +02:00
Pieter-Jan Briers
fe7aa87536 Fix scsi script responses. 2020-10-20 12:04:46 +02:00
20kdc
d2949ac474 Polar coordinate lighting implementation (#1324) 2020-10-19 22:39:07 +02:00
DrSmugleaf
6eb3301904 Add debug assert for transform self parenting (#1340) 2020-10-19 22:20:42 +02:00
Víctor Aguilera Puerto
e3f2e36ad4 Update Eye test to reflect new defaults. 2020-10-17 17:44:21 +02:00
metalgearsloth
4a8c84d948 Fix even more physics jank (#1338)
* Fix even more physics jank

* Minor tweaks

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Víctor Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
2020-10-17 17:42:22 +02:00
metalgearsloth
d2b46ca522 Fix physics cam (#1337)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-17 17:37:06 +02:00
Víctor Aguilera Puerto
8b3348d4c1 Eye zoom is 0.5 by default.
Let's be honest, this is what most mobs' eyes will default to.
2020-10-17 13:10:09 +02:00
Víctor Aguilera Puerto
b41bd56dce Serialize mass correctly in PhysicsComponent. 2020-10-16 13:22:52 +02:00
Pieter-Jan Briers
0eb9cbfffb Fix incorrect alpha blend funcs.
This caused showbb to allow you to see stars.
2020-10-15 20:06:02 +02:00
Pieter-Jan Briers
1815e6dac9 VVPropEditorTimeSpan 2020-10-15 01:26:49 +02:00
Pieter-Jan Briers
f8c8f0e126 Rename ViewVariablesPropertyEditor to VVPropEditor. 2020-10-15 01:04:40 +02:00
Pieter-Jan Briers
b14d057709 TypeSerializer for TimeSpan. 2020-10-15 01:03:24 +02:00
Exp
599b9eaa15 Fixes VV Number Fields crashing on invalid input (#1334) 2020-10-14 23:06:27 +02:00
DrSmugleaf
3176d4c06e Rename last usages of Collidable to Physics (#1333) 2020-10-14 22:42:01 +02:00
DrSmugleaf
80db55153e Expose EntitySystemManager.AllSystems property (#1332) 2020-10-14 22:40:42 +02:00
ShadowCommander
8f749c2421 Fix UI keybinds stopping after the first (#1328) 2020-10-14 18:14:17 +02:00
metalgearsloth
c0e66d725a Stop redundant appearance data from being sent (#1326)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-14 18:12:22 +02:00
DrSmugleaf
3b56affe9a Add IConfigurationManager.SetCVar for CVarDef (#1329) 2020-10-14 18:06:10 +02:00
Paul Ritter
f131f367d8 Componentdependency (#1311)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
Co-authored-by: Víctor Aguilera Puerto <zddm@outlook.es>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
2020-10-13 14:22:45 +02:00
Pieter-Jan Briers
50311afe9f Group VV members lists by declaring type. 2020-10-13 13:43:50 +02:00
metalgearsloth
bc87f2ea9c Pause refactor (#1314)
* Refactor pausing

* Sprite as well woops

* Bring PauseManagerExt back with [Obsolete] so that content compiles.

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-10-12 18:16:20 +02:00
Pieter-Jan Briers
6102ee80ec Make math types mutable. 2020-10-12 17:38:24 +02:00
Pieter-Jan Briers
2386fedd25 Update Lidgren 2020-10-12 17:07:09 +02:00
Víctor Aguilera Puerto
33467d6e23 PlacementHijack can now prevent rotating. 2020-10-12 14:21:53 +02:00
Víctor Aguilera Puerto
022e044b69 Fix Entity Spawn Menu Eraser mode not clearing when closing it.
Fixes https://github.com/space-wizards/space-station-14/issues/2178
2020-10-12 14:02:35 +02:00
Víctor Aguilera Puerto
7784a41567 Adds LayerCount property to server-side SpriteComponent 2020-10-12 12:50:36 +02:00
DrSmugleaf
75238b183b Fix chunk to string test and PhysicsComponent file name (#1321)
* Fix chunk to string test and PhysicsComponent file name

* AAAAAAAAA

* Fix accidentally deanchoring everything
2020-10-12 01:01:27 +02:00
DrSmugleaf
f8d5fa5319 Rename CollidableComponent to PhysicsComponent (#1320) 2020-10-11 15:32:50 +02:00
DrSmugleaf
5bbcdbd3ef Add back Vector2i.ToEntityCoordinates (#1319) 2020-10-11 15:15:22 +02:00
DrSmugleaf
b1a09db07b Remove obsolete physics component (#1317) 2020-10-11 14:39:22 +02:00
DrSmugleaf
da76788751 Replace MapIndices to Vector2i (#1318) 2020-10-11 14:33:09 +02:00
metalgearsloth
29086a5b4b Mark MapIndices as Obsolete (#1316)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-11 13:34:38 +02:00
Pieter-Jan Briers
cabb9859ec Move Lidgren to submodule 2020-10-10 23:32:37 +02:00
metalgearsloth
672c3d7680 Make sprite error more helpful (#1313)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-10 12:05:27 +02:00
metalgearsloth
5f1251a813 LocalPosition value check (#1312)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-10 12:05:06 +02:00
ShadowCommander
6b769d814e Fix ScrollBar overshot when frame time is long (#1310) 2020-10-10 01:10:03 +02:00
Pieter-Jan Briers
e2b97d3eac Fix viewports getting cleared to #fff0 instead of #0000. 2020-10-09 15:06:24 +02:00
Paul Ritter
56b85256bf Things needed for singulo (#1306)
* things

* direction loopup table

* spinbox lineedit isvalid wasn't using isvalid
spinbox disabled functions

* fixes placementmanager

* pjb fixes
2020-10-09 14:55:19 +02:00
metalgearsloth
00fbefa4e5 Physics caching go brrt (#1307)
* Physics caching go brrt

* Minor optimisation

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-09 11:40:02 +02:00
DrSmugleaf
23c0984d2e Change integration tests to use LoginType.GuestAssigned instead of Guest (#1308) 2020-10-09 11:38:53 +02:00
metalgearsloth
c34eaa822f Fix debug fonts (#1309)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-09 11:37:01 +02:00
Pieter-Jan Briers
e16e9f1786 Fix bad ANGLE downloads 2020-10-06 15:12:01 +02:00
Pieter-Jan Briers
ade03ceb13 Adds non-predicate FirstOrNull. 2020-10-06 15:03:27 +02:00
Pieter-Jan Briers
681741c298 ANGLE natives now included. 2020-10-06 11:21:05 +02:00
Pieter-Jan Briers
496c79a99c Native dependencies update
Use GLFW 3.3.2

OpenAL build for Linux
2020-10-06 11:00:29 +02:00
Jan Nekvapil
5bf4e9ae1a Scale frame debug into control boundaries (#1305)
* Scale frame debug into control boundaries

* Remove unnecessary  cache
2020-10-06 09:47:50 +02:00
Víctor Aguilera Puerto
c96d5933d5 Changes needed for construction (#1304)
* Placement improvements

* Slightly better YAML error
2020-10-06 01:55:04 +02:00
DrSmugleaf
aa6c0942c0 Add component references for SpriteComponent (#1303)
* Add component references for SpriteComponent

* Add RegisterComponent attribute

* Fix tests

* Revert "Fix tests"

This reverts commit 6d6b9dedd0.

* Revert "Add RegisterComponent attribute"

This reverts commit 09d6610f8a.

* Add component references manually
2020-10-06 01:46:36 +02:00
Pieter-Jan Briers
51df6dbef5 Allow TextureRect to have shaders applied to it. 2020-10-06 01:28:47 +02:00
DrSmugleaf
8dc78cdfec Add YAML serialization for nullable primitive types (#1299)
* Add YAML serialization for nullable primitive types

* Add tests and fix null serialization

* Merge primitive and nullable primitive checks

* Fix null primitive serialization test

* This kills the analyzer
2020-10-03 15:29:27 +02:00
metalgearsloth
90a4ec7606 EffectSystem excluded sessions (#1301)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-02 14:58:16 +02:00
DrSmugleaf
9a809040a8 Add HashSet YAML serialization (#1291)
* Add HashSet YAML serialization

* consider this

* Revert "consider this"

This reverts commit f542f2c0bf.

* you think you are so funny c#

* Remove reflection call, fix equals and add tests

* Make this code slightly less bad

* Fix hashset equality and add test
2020-10-02 14:52:26 +02:00
metalgearsloth
ec4db71478 PlayerSession helper (#1300)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-10-02 14:51:13 +02:00
Jan Nekvapil
6ac180ef7d Fix monitoring descriptions (#1302) 2020-10-02 14:50:13 +02:00
Víctor Aguilera Puerto
7aaeac81b0 Use EnsureComponent in ContainerManagerComponent
Just a small change.
2020-09-29 17:34:42 +02:00
Pieter-Jan Briers
99aab96694 Fix offset control outline debug rendering. 2020-09-29 15:00:37 +02:00
Pieter-Jan Briers
9410cb4b45 Ah fuck. 2020-09-29 14:49:39 +02:00
Pieter-Jan Briers
aa64528a03 Auth (#1289)
* Some stuff for auth

* Holy crap auth works

* Enable encryption even if no auth token is provided.

It's still possible that the public key was retrieved over HTTPS via the status API, in which case it will be secure.

* Fix integration test compile.

* Secure CVar API.

* Literally rewrite the auth protocol to be minecraft's.

* Better exception tolerance in server handshake.

* Auth works from launcher.

* Fix some usages of UserID instead of UserName

* Fix auth.server CVar

* Kick existing connection if same account connects twice.

* Username assignment, guest session distinguishing.

* Necessary work to make bans work.

* Expose LoginType to OnConnecting.

* Fixing tests and warnings.
2020-09-29 14:18:12 +02:00
DTanxxx
e7a49cc1f0 Removed obsolete EntitySpawnWindow constructor (#1295)
Co-authored-by: David Tan <>
2020-09-29 13:38:42 +02:00
metalgearsloth
4dd0f99374 Make AI processors equatable (#1293)
* Make AI processors equatable

* Slightly less braindead

* Fix dat null

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-09-29 13:37:08 +02:00
DrSmugleaf
ab86b59bc8 Fix build (#1298) 2020-09-28 23:18:34 +02:00
DrSmugleaf
fa75ffbb94 Fix build (#1297)
* Fix build nullable errors

* Fix the rest
2020-09-28 21:09:11 +02:00
Paul Ritter
7b1f60c940 Readds Iconcomponent (#1296)
* yep

* directional texture
2020-09-28 20:54:29 +02:00
Pieter-Jan Briers
b69aa3c062 Oops 2020-09-26 13:32:29 +02:00
Pieter-Jan Briers
0c6d612723 Wow I really messed that up huh. 2020-09-25 22:09:24 +02:00
Pieter-Jan Briers
7de08ac592 Define CVars in a central location.
Instead of a bunch of RegisterCVar<> calls, it's now similar to Key Functions.
2020-09-25 21:21:18 +02:00
Pieter-Jan Briers
e87520bea5 Occluder tree for server. 2020-09-24 18:14:24 +02:00
Víctor Aguilera Puerto
695d8318d0 Make GetPrototypeIcon use a dummy entity to fix a crash (#1294)
* Make GetPrototypeIcon use a dummy entity to fix a crash

* Nullability
2020-09-24 17:30:19 +02:00
Pieter-Jan Briers
d7526e61bb Fix raycasting and tests. 2020-09-24 16:00:54 +02:00
20kdc
8b2b032528 Improve fallback soundfont and remove aliased patterns (#1292)
* Improve fallback soundfont and remove aliased patterns

* Better fallback soundfont: Fix tuning

* Better soundfont: Even more improvements
2020-09-24 14:53:40 +02:00
Pieter-Jan Briers
d134f31d66 Re-implement DynamicTree<T> on top of B2DynamicTree<T>. 2020-09-24 11:51:50 +02:00
Pieter-Jan Briers
bfd2fa1018 Fixes for B2DynamicTree 2020-09-24 11:50:37 +02:00
Pieter-Jan Briers
4ce4fb9a9f A more true-to-Box2D DynamicTree.
It's fast.

Could still do with some bounds check elimination I guess.
2020-09-23 19:48:31 +02:00
DTanxxx
ff32a70b10 Purge localization manager (#1285)
* Applied feedback

* Applied feedback

Co-authored-by: David Tan <>
2020-09-23 16:21:10 +02:00
Paul Ritter
827734d658 Nukes the Iconcomponent (#1290)
* removes iconcomponent

* forgot one thing

* it works!!11

* last change
2020-09-23 16:20:32 +02:00
Víctor Aguilera Puerto
991aabe8a2 Fix ClientEntityManager's entity creation
It hadn't been correctly translated to use EntityCoordinates
2020-09-22 13:09:37 +02:00
Víctor Aguilera Puerto
f1334ca57d Adds proper attribution and license for fallback soundfont 2020-09-19 19:23:22 +02:00
DrSmugleaf
25aaac7dbf Make the tile spawn search bar autofocus (#1287) 2020-09-17 23:19:17 +02:00
Swept
0febea16da Toggle FOV command (#1288)
* Initial

* Thanks Exp
2020-09-17 23:18:58 +02:00
DTanxxx
8dc3723c09 Make more fields VV and editable (#1284)
* Make more fields VV and editable

* Applied feedback

Co-authored-by: David Tan <>
2020-09-17 23:17:46 +02:00
Pieter-Jan Briers
f926698db0 Fix texture swizzle on GLES3.
ES doesn't support the combined swizzle parameter so we have to  set them separately.
2020-09-16 00:54:11 +02:00
DrSmugleaf
4cbdde6ec3 Make GetTilesIntersecting translate from world to local to tile (#1286) 2020-09-11 19:20:24 +02:00
Víctor Aguilera Puerto
ab0c135fbf ViewVariables for grids 2020-09-11 13:03:57 +02:00
Pieter-Jan Briers
874995225b I blame rider for all my faults. 2020-09-10 11:55:25 +02:00
Pieter-Jan Briers
a8c4270834 Fix mixup of KHR suffix debug functions. 2020-09-10 11:40:21 +02:00
derek
9cc9b68e09 Toggle function in BoundUserInterface (#1283)
* add toggle

* Update Robust.Server/GameObjects/Components/UserInterface/ServerUserInterfaceComponent.cs

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-09-08 18:54:03 +02:00
Exp
31e9554cd7 Makes more fields VV (#1282)
* Sprite & Appearance VV

* Added Client SpriteComp & RSI
2020-09-08 18:44:53 +02:00
Pieter-Jan Briers
a72d2beb86 Ignore that. 2020-09-07 21:53:39 +02:00
Pieter-Jan Briers
cce8d81bcf Add Histogram metrics for per-system time usage. 2020-09-07 21:50:08 +02:00
Víctor Aguilera Puerto
1181464829 Add RotateEvent raised when a Transform's LocalRotation changes. 2020-09-07 13:56:34 +02:00
Pieter-Jan Briers
a19e12e693 display.uiScale 0 (the new default) pulls UI scale from OS. 2020-09-07 12:58:44 +02:00
Pieter-Jan Briers
e60ecfad49 Enable bilinear filtering for logo. 2020-09-07 12:18:05 +02:00
Pieter-Jan Briers
4e6f8ca224 Remove OptionsMenu from engine. 2020-09-07 11:07:49 +02:00
20kdc
5146bf8ac2 More configurable lighting (also, "Rounded" mode for Range) (#1274)
* Add support for 'Rounded' mode to Range (and thus Slider)

* Make lighting resolution more configurable

* Use a lighting presets dropper because RemieRichards said so

* Make ConfigLightingQuality not a property and instead two separate methods

* More configurable lighting: cleanup to use a switch rather than an if-chain
2020-09-07 10:57:44 +02:00
Pieter-Jan Briers
1eb03eb339 Various modifications to the input manager to allow key rebinding. 2020-09-07 10:55:41 +02:00
Pieter-Jan Briers
f3398853c1 Adds more file opening convenience methods. 2020-09-07 10:55:40 +02:00
Pieter-Jan Briers
81c299e40d Adds UIRightClick key function. 2020-09-07 10:55:40 +02:00
Pieter-Jan Briers
e80b6a238d Add Keyboard.Key.IsMouseKey().
I needed this for something but didn't end up using it, whatever.
2020-09-07 10:55:40 +02:00
Pieter-Jan Briers
482c8e1317 Fix ISelfSerialize serialization. 2020-09-07 10:55:40 +02:00
Acruid
f66ad68848 Pulls ClientSendMessage up from IClientNetManager to INetManager, so that a shared context on the client can actually send net messages, like the server. 2020-09-06 09:35:54 -07:00
Acruid
2b3f419e3c Adds PeekStringSize() to the lidgren netbuffer, which allows you to get the size in bytes of the string without actually decoding the string. 2020-09-06 09:30:55 -07:00
Víctor Aguilera Puerto
794e5a1d5c Fix missing method in IMapGrid 2020-09-06 17:03:13 +02:00
DrSmugleaf
0a67cecfa5 Replace every usage of GridCoordinates with EntityCoordinates (#1280)
* Added struct skeleton for EntityCoordinates.

* Polish EntityCoordinates, add tests, add EntityCoordinates to Transforms

* Doc cleanup

* Remove useless code

* Return offset 0 when you don't have a parent

* Test for making sure EntityCoordinates for entities without parents have offset 0

* Use parent transform's GridId for GetGridId.

* Adds various methods, checks and tests

* Replace GridCoordinates with EntityCoordinates

* EyeManager.WorldToScreen fix

* Address reviews

* Fix za buildo

* Fix one transform test

* Fix the remaining tests

* Remove duplicate

* Remove another merge duplicate

* Fix property

* Rename most usages of GridCoordinates to EntityCoordinates.

* Add WithEntityId method to EntityCoordinates.

* Fix EntityCoordinates usage in GetEntitiesInRange

* Remove cursed IMapGrid method, change naming.

* Makes GridTileLookupSystem use EntityCoordinates

Co-authored-by: Acruid <shatter66@gmail.com>
Co-authored-by: Víctor Aguilera Puerto <zddm@outlook.es>
2020-09-06 16:09:19 +02:00
Víctor Aguilera Puerto
ec2fa6e86e Fix GridTileLookupSystem trying to get deleted entities' components on Round Restart 2020-09-06 15:48:36 +02:00
metalgearsloth
664e6a00ee Grid tile lookup system (#1281)
* Grid tile lookup system

* Make grid updates better for lookup

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-09-06 15:43:18 +02:00
Víctor Aguilera Puerto
0701b040ee EntityCoordinates (#1277)
* Added struct skeleton for EntityCoordinates.

* Polish EntityCoordinates, add tests, add EntityCoordinates to Transforms

* Doc cleanup

* Remove useless code

* Return offset 0 when you don't have a parent

* Test for making sure EntityCoordinates for entities without parents have offset 0

* Use parent transform's GridId for GetGridId.

* Adds various methods, checks and tests

* Adds new constructor to EntityCoordinates and add WithPosition method

Co-authored-by: Acruid <shatter66@gmail.com>
2020-09-04 23:08:18 +02:00
DrSmugleaf
d9f5c7d7b5 Add NextMapId and NextGridId to IMapManager (#1279) 2020-09-03 21:38:46 +02:00
20kdc
49242f8a0a Auto-replace texture2D with texture to fix issues with deprecated function names (#1278) 2020-09-03 19:15:09 +02:00
nuke
17402b69f7 Add Color.ToHexNoAlpha (#1275) 2020-09-03 14:36:51 +02:00
20kdc
7736882da2 GLES2: Support for GL_OES_standard_derivatives (fixes wall brightening when available) (#1276) 2020-09-03 09:38:17 +02:00
DrSmugleaf
1a453a0d23 Make HighestMapID and HighestGridID public for content to read (#1271) 2020-09-02 23:07:41 +02:00
Pieter-Jan Briers
b4fac5256c More Clyde GL version things.
Correctly use KHR and OES suffixed functions for debug output and VAOs, if necessary.

Allow overriding the detected GL version for feature detection (nvidia gives me an ES 3.2 context even when ES 2.0 is requested, so...)
2020-09-02 22:10:50 +02:00
ShadowCommander
72d8f60846 Add debug highlighting for UI Controls (#1272) 2020-09-02 12:32:30 +02:00
Pieter-Jan Briers
3ea73e9d2a Various OpenGL fixes.
1. Fixes screenshots on ES by providing a fallback path for when encessary features (PBO, fence sync, mapbuffer) are not available.
2. Correctly detect fence sync as not always being available for 3.1
3. Remove the "bad OpenGL version" box. We have MessageBoxW now.
4. Separated feature detection for ES and Desktop, added more feature detections on various sides.
5. Moved GL feature detection to its own file.
2020-09-02 01:47:12 +02:00
20kdc
4f5d2664b8 Prevent gl_FragColor deprecation issues on GL3.3 (hopefully finally ending the saga of hotfixes) (#1270) 2020-09-01 20:40:55 +02:00
Víctor Aguilera Puerto
eab9335886 Actually use argument in MapGrid GetAllTiles 2020-09-01 17:38:53 +02:00
20kdc
880be34b8d GLES2: hotfix: Use in/out to prevent core profile complaints (#1269) 2020-09-01 17:25:06 +02:00
20kdc
4777a0adbf GLES2 users, assemble! (#1266) 2020-09-01 15:27:14 +02:00
Pieter-Jan Briers
c5573c0d33 Fix unit tests. 2020-09-01 01:13:12 +02:00
Pieter-Jan Briers
3f43e86530 NetMessageAccept, NetMessage dispatch cleanup.
Net message functions are now cached when the message is registered or the string table updates (client side). This removes the cache call from DispatchNetMessage.

Receiving net messages that we don't have reception callbacks for, or that are blocked with the new NetMessageAccept enum, will instantly cause the net manager to drop the offending connection to avoid malicious use.

This means trying to send string tables to the server will just result in an instant kick without even hitting ReadFromBuffer().

This allows us to move some if() checks to asserts.
2020-09-01 01:03:06 +02:00
Pieter-Jan Briers
36f29d54ed Mapped string serializer cleanup and fixes. 2020-08-31 22:58:42 +02:00
Víctor Aguilera Puerto
59a003cda0 Add path to RSI class 2020-08-31 20:45:45 +02:00
Víctor Aguilera Puerto
f25318a096 Fix IEntityManager doc 2020-08-31 20:45:24 +02:00
nuke
0b1b496caf Make more light properties animatable (#1267) 2020-08-30 17:03:34 +02:00
Víctor Aguilera Puerto
524177550f Fix YamlFlagSerializer doc 2020-08-30 15:00:10 +02:00
ShadowCommander
89dca78d18 Fix Button Labels not updating styles when Button is disabled/enabled (#1263)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-08-30 00:12:56 +02:00
metalgearsloth
6ffe2e1750 Effect entity parenting (#1264)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-08-29 12:59:18 +02:00
Pieter-Jan Briers
5faa8a59c1 Add some [Pure] annotations. 2020-08-29 07:53:50 +02:00
Pieter-Jan Briers
6b92db35f0 Deterministic RobustMappedStringSerializer (#1265) 2020-08-29 07:53:29 +02:00
Acruid
5261c8d5aa Exposes the IEntitySystemManager on the IEntityManager.
Adds a ToString override to InputCmdMessage.
2020-08-27 13:02:31 -07:00
Pieter-Jan Briers
0f38d7f7a1 Suppress collision regeneration while updating chunk from game state.
Tiny optimization.
2020-08-27 02:24:27 +02:00
Pieter-Jan Briers
0682dcf98c Sprinkle glGetError everywhere. 2020-08-27 02:11:46 +02:00
Swept
cd1d6035e5 Control.cs (#1262) 2020-08-27 00:31:12 +02:00
Pieter-Jan Briers
4967238202 Don't throw in ISpriteLayer.EffectiveDirection if invalid state. 2020-08-26 19:35:31 +02:00
Pieter-Jan Briers
c0262ec6f5 Always make Vector2i serializable.
Fixes https://github.com/space-wizards/space-station-14/issues/1898
2020-08-26 17:41:00 +02:00
Pieter-Jan Briers
56d0f04c05 Committing debug logs ftw. 2020-08-26 17:24:25 +02:00
Pieter-Jan Briers
ee9d107be5 Apply multiple game states at once if game state buffer overflowing above threshold.
Fixes #1252
2020-08-26 16:28:25 +02:00
Pieter-Jan Briers
f5e23fc710 Fix Lidgren crashing if lo is the only available network adapter. 2020-08-26 16:25:31 +02:00
Pieter-Jan Briers
3f0e2fa429 Fix GameStateProcessor skipping over necessary game states in some extrapolation cases.
Fixes #1246
2020-08-26 13:45:15 +02:00
Pieter-Jan Briers
cd5115fa85 The comment was right there, man. 2020-08-26 01:01:18 +02:00
Exp
904869cc68 Allows CVars to be listed (#1259) 2020-08-25 23:26:02 +02:00
metalgearsloth
09b1718d0a IsIntersecting method for EntityManager (#1254)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-08-25 23:25:32 +02:00
Pieter-Jan Briers
0b67c00057 Make a Windows message box if the game window can't be opened (#1260) 2020-08-25 23:23:55 +02:00
Pieter-Jan Briers
381cdb5fbb Add OpenGL 3.1 support.
h
2020-08-25 21:44:01 +02:00
Pieter-Jan Briers
9b77085626 Log exception to server console on client command ExecuteError. 2020-08-25 21:33:24 +02:00
Pieter-Jan Briers
7890c1b39c Fix bogus nullability errors from Rider.
None of these are actual nullability warnings but they make Rider shut up so.
2020-08-25 17:48:23 +02:00
Exp
584e540bb2 Admin Menu Engine PR (#1219) 2020-08-25 14:58:24 +02:00
DrSmugleaf
ad2545d83d Add nullable API methods for getting components and user interfaces (#1241) 2020-08-22 13:56:05 +02:00
Pieter-Jan Briers
6133ba77ca Change Prometheus tick time histogram to better fit. 2020-08-21 22:31:07 +02:00
Víctor Aguilera Puerto
afc5aa1075 Dispose of MIDI renderers on the MIDI thread (#1248) 2020-08-21 20:39:36 +02:00
Pieter-Jan Briers
865610df1e Fix IMapManager.CreateNewMapEntity not initializing the created entity. 2020-08-21 17:15:18 +02:00
Pieter-Jan Briers
f0824212da Make container shutdown more sane.
Fixed removal of deleted entities from their parent container not working if one of said parent's other containers got deleted at some point.
2020-08-21 14:53:48 +02:00
metalgearsloth
31f44027a1 Add PlayerSession exclude for audiosystem (#1243)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-08-21 14:53:38 +02:00
Pieter-Jan Briers
68d80cb136 Fix exceptions in audio system update. 2020-08-20 21:34:40 +02:00
Pieter-Jan Briers
90108f66ae Fix unplayable streams not disposing audio sources immediately. 2020-08-20 21:34:23 +02:00
Pieter-Jan Briers
79b3b51498 Fix bad #region. 2020-08-20 20:46:03 +02:00
Pieter-Jan Briers
cc8addd34e Adds integer clamps. 2020-08-20 20:45:52 +02:00
Pieter-Jan Briers
0958ce3e51 MathHelper make use of MathF better. 2020-08-20 20:41:22 +02:00
Pieter-Jan Briers
0d7e6a8e1c Fix loading config. 2020-08-20 20:31:01 +02:00
Visne
9d1bec9bb2 Merge FloatMath and MathHelper (#1234)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-08-20 19:21:07 +02:00
Pieter-Jan Briers
21d493a6ec Ensure that paths are rooted in WritableDirProvider. 2020-08-20 18:52:31 +02:00
Pieter-Jan Briers
2fb60f7129 Actually disable runtime log output in integration tests. 2020-08-20 18:52:31 +02:00
Pieter-Jan Briers
3148371d18 Use virtual file system on server integration tests. 2020-08-20 18:52:31 +02:00
Pieter-Jan Briers
3fa2cece72 Allow disabling runtimelog output.
Necessary for parallel integration tests.
2020-08-20 18:52:30 +02:00
Pieter-Jan Briers
773ea34ee3 Make integration tests TearDown OneTimeTearDown.
Fixes concurrency issues.
2020-08-20 18:52:30 +02:00
Pieter-Jan Briers
00f914d212 Fix read/write issues with VirtualFileStream.
This one was pretty obvious and silly.
2020-08-20 18:52:30 +02:00
DrSmugleaf
31ff253fc0 Replace assert with nullable operator (#1242) 2020-08-20 16:38:56 +02:00
Pieter-Jan Briers
d4fc0517c4 Fix IEntity.TryGetComponent nullability signatures.
This means all invocations of TryGetComponent now need a nullable parameter because, well, the result can be null. that's the point.
2020-08-20 15:31:18 +02:00
Acruid
1513389fc1 Adds a property to IoCManager that gives access to the IDependencyCollection singleton of the thread. 2020-08-18 16:29:57 -07:00
Acruid
b1a19e8942 Adds the ability to register a single prototype class with the PrototypeManager. 2020-08-18 15:20:32 -07:00
Acruid
6245b2223b Improve performance when initially settling the map at load time.
Clients now simulate all awake bodies when predicting, not just predicted ones.
2020-08-18 10:59:49 -07:00
Acruid
63fca2fb3a Adds the 'rmcomp' console command, for manually removing components from entities. 2020-08-18 10:25:35 -07:00
DrSmugleaf
15ee6a42be Add component message for an entity moving (#1180)
* Add component message for an entity moving

* Bring EntityMovementMessage out of the container check

* Make entity movement messages use one instance and mark PublicAPI
2020-08-16 18:17:28 -07:00
Pieter-Jan Briers
c72ea7194e Add RequestWindowAttention API. 2020-08-16 23:21:07 +02:00
Pieter-Jan Briers
559d890128 Fix exceptions falling through in NetManager.DispatchNetMessage 2020-08-16 21:49:23 +02:00
Pieter-Jan Briers
da43d56680 Add command filtering to list command. 2020-08-16 16:59:08 +02:00
DrSmugleaf
8d060e69af Fix physics bodies not being woken up when changing a controller's velocity (#1235) 2020-08-16 16:23:29 +02:00
Pieter-Jan Briers
688ec89d43 Dump ToString() when component not found. 2020-08-16 14:49:48 +02:00
Pieter-Jan Briers
d18319bd7b Entities now show if they are deleted in ToString() 2020-08-16 14:49:48 +02:00
Vince
6a546dadf1 Fixes most warnings (#1233) 2020-08-16 14:04:15 +02:00
Pieter-Jan Briers
a6273cf1a1 Don't include assembly strings into the string dict.
This is a pretty awful idea and it wastes a lot of bandwidth.
2020-08-16 02:40:59 +02:00
Pieter-Jan Briers
e828a9d8c8 Remove bad usage of Lazy<> from RobustMappedStringSerializer. 2020-08-16 02:40:22 +02:00
Pieter-Jan Briers
562901e8e7 Fix exceptions from netchannel disconnecting during handshake. 2020-08-16 02:19:57 +02:00
Pieter-Jan Briers
5637669876 Allows VV to read KeyValuePair<,>s over the network.
This required a bit of refactorings and improvements but oh well.
2020-08-16 01:59:01 +02:00
Pieter-Jan Briers
1e89c5f1fd IWritableDirProvider does not allow access to parent directories.
Fixes #1229

Added tests.
2020-08-16 01:32:19 +02:00
Pieter-Jan Briers
1934428c95 Use better file access patterns in engine. 2020-08-16 01:08:07 +02:00
Pieter-Jan Briers
4f5e1d5650 Improve IWritableDirProvider API:
Added Open() method that takes in FileMode, FileAccess AND FileShare.
Added extra extension method helpers and made use of better FileAccess/FileShare modes.
2020-08-16 01:06:42 +02:00
Pieter-Jan Briers
6889e2cba3 Fixes FrameUpdate getting 0 dt when paused.
Fixes #1226
2020-08-15 16:35:32 +02:00
Víctor Aguilera Puerto
5819e5ee92 Adds GetCardinalDir extension 2020-08-15 03:18:51 +02:00
Pieter-Jan Briers
08b7550a85 Allow VVing IPlayerManager on the server. 2020-08-15 01:12:13 +02:00
ShadowCommander
8b931fc56e Fix input handling and stop input when a cmd returns true (#1222) 2020-08-15 00:31:09 +02:00
SoulSloth
fe1e37d8df Fix melee audio on entity destruction (#1192) 2020-08-15 00:30:45 +02:00
DrSmugleaf
7bfd5eb72e Add NetSerializer dictionary test (#1214)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-08-14 23:55:07 +02:00
Pieter-Jan Briers
af261d32ef Load PDBs even on FULL_RELEASE. 2020-08-14 23:54:24 +02:00
DrSmugleaf
5c10050f9e Add NetSerializer HashSet test (#1213) 2020-08-14 23:27:17 +02:00
Pieter-Jan Briers
60942545f6 Update NetSerializer 2020-08-14 23:09:09 +02:00
Exp
73d529386d Added Console Tab Completion (#1212)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-08-14 22:47:26 +02:00
Acruid
c7f5521d2e Removed IsEntityPaused from the server component query, it was bugged and only about 1/5 of the entities on the map were actually processed in the collision system. This change causes a noticeable perf impact when starting the server and lasting until everything on the map goes to sleep.
BodyType is now serializable, fixes bug with VV.
Moved both velocity properties from ICollidableComponent to IPhysBody, added default methods to IPhysBody to get the word transform.
Added DebugTools.Break() method, calling it breaks execution in the attacked debugger.
Added VV attributes to various CollidableComponent properties.
2020-08-13 21:52:53 -07:00
Víctor Aguilera Puerto
58b6e18030 Adds new macros for to be and have english verbs. 2020-08-14 02:43:46 +02:00
Pieter-Jan Briers
d4a47778ef Remove this parameter from FloatMath.Clamp.
That was a stupid idea.
2020-08-12 21:17:18 +02:00
Pieter-Jan Briers
b45ea725d7 Remove CannyFastMath. 2020-08-12 21:17:17 +02:00
Víctor Aguilera Puerto
5bb3bc7083 Remove CannyFastMath usage from Box2 and Box2i. 2020-08-12 21:02:13 +02:00
Víctor Aguilera Puerto
9ca48a0375 Revert fix attempt.
Be sure to always check what branch you've checked out, people.
2020-08-12 18:01:49 +02:00
Víctor Aguilera Puerto
ef4c807498 Attempt to fix grid 0 bug. 2020-08-12 17:57:25 +02:00
Víctor Aguilera Puerto
a3dfa49798 Fix typo in lidgren 2020-08-11 17:51:19 +02:00
DrSmugleaf
d407fecab5 Add ContainerHelpers method to check if an entity is in the same container as another or both are in none (#1216) 2020-08-10 16:38:28 +02:00
Acruid
64a3916c04 Added the Robust.Physics project.
Added BenchmarkDotNet to the Robust.UnitTesting project.
2020-08-09 13:43:57 -07:00
Acruid
6c3c22affe Added AlignedRectangle (Box2) collision features. 2020-08-09 01:23:03 -07:00
Acruid
c4899069c6 Added sleep culling to physics bodies, noticeable perf gains.
Bodies without velocity are considered for collision, lockers are fixed.
Added force/torque integration to physics bodies.
Friction is now tickrate agnostic.
2020-08-09 01:16:55 -07:00
ike709
55bcbaaca2 Fix player jittering when colliding with a wall (#1218) 2020-08-09 04:30:24 +02:00
Acruid
7d74c02c8d Fixed a bug with overlay drawing arguments.
Added mouse hover info about collision bodies in the collision overlay.
2020-08-08 16:56:14 -07:00
ShadowCommander
444eecf339 Change BaseWindow and SS14Window to open where they previously closed (#1217)
First open will be top left, centered, or left vertically centered. The subsequent calls to open will open the window at the position the window was closed at.
2020-08-09 00:13:09 +02:00
Acruid
5d2e3a4c61 Minor API improvements. 2020-08-06 22:00:20 -07:00
ShadowCommander
97f0479676 Fix OpenCentered by setting size before position (#1211) 2020-08-06 15:53:37 +02:00
Pieter-Jan Briers
a25861461e Small GLES compat fix.
Makes glTexImage2D call in render target creation pass legal arguments for GLES.
2020-08-06 13:31:55 +02:00
L.E.D
b983863c90 fix deleted entity exception (#1208) 2020-08-03 00:40:59 +02:00
Víctor Aguilera Puerto
714e51c0e1 Remove proof of concept for gas. 2020-08-02 21:14:50 +02:00
ShadowCommander
e5ae2182b0 Make timer more accurate when repeating (#1206) 2020-08-02 19:48:55 +02:00
Víctor Aguilera Puerto
44bcbfa8e5 Misc changed needed for atmos (#1186)
* Add needed changes for atmos

* Get delays for RSI state

* Placement hijack can handle deletion on gridcoordinates

* Array serialization

* MapIndices to GridCoordinates

* CollidableComponent creates VirtualControllers using IDynamicTypeFactory

* Probability assert now prints chance

* Remove unused stuff, fix build

* Update documentation for map indices

* readability

* Removed unused using statements

* Remove ToAngle

* Fix messed up merge

* Fix MapIndices/GridCoordinates conversion

* Add "invalid" direction.

* Update Robust.Shared/Serialization/YamlObjectSerializer.cs

* Nullable fix

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-08-02 18:39:23 +02:00
SoulSloth
e21cf79ee4 Made Point Light Radius Animatable (#1207) 2020-08-02 17:33:08 +02:00
Acruid
08edc2a3a9 Fix bug where PhysShapeCircle was not raising it's changed event when changing radius.
Made PhysShapeCircle public.
2020-08-02 00:03:58 -07:00
Acruid
8e2914d520 Enums are hard :(
This fixes screenspace overlays not showing up, like flash and net graph.
2020-07-31 23:38:41 -07:00
Acruid
900bf76a7d Attempt #2 to fix the timing bugs. CurTime increases again, and all the unit tests pass this time.
This resolves https://github.com/space-wizards/space-station-14/issues/1560.
Special thanks to PJB's prediction unit tests.
2020-07-31 23:20:35 -07:00
Acruid
ca297ee739 Removed EnumHelper.TryParse because the .Net devs got around to adding a non-generic version of Enum.TryParse. 2020-07-31 14:12:19 -07:00
Acruid
a5125a0561 Allows Overlays to draw to multiple spaces on the screen.
Removed Overlay.Shader property, you need to manage the field yourself and apply the shader before you draw.
Made all overlays compatible with the new changes.
2020-07-31 14:00:12 -07:00
Acruid
3fd1a2f3fb Fill out cases for the shape switch.
Circle-Box collisions!

Circle Collisions!

PhysShapeCircle!
2020-07-31 12:02:41 -07:00
Acruid
2b692d596e Stops the GameTiming class from blindly caching the curTime constantly, regardless of it was in prediction/simulation or not. This seems to completely solve the issue of CurTime being negative. As long as Tickrate is only changed when processing the latest server state (not half way through prediction), everything should be OK. 2020-07-30 17:20:52 -07:00
Pieter-Jan Briers
53288ffd2b YamlObjectSerializer.IsSerializedEqual now handles dictionaries. 2020-07-31 01:44:56 +02:00
Pieter-Jan Briers
f0c59f21b0 Fix AppVeyor 2020-07-30 23:11:03 +02:00
Pieter-Jan Briers
ac32042ab3 Good job there forgetting to update AppVeyor 2020-07-30 18:48:11 +02:00
Pieter-Jan Briers
ba622bf457 Update NetSerializer again so the dirty file is gone.
This change literally does not affect us but whatever.
2020-07-30 18:46:33 +02:00
Pieter-Jan Briers
f2b779d964 Remove engine BuildChecker.
It apparently has been broken for over a year and I trust anybody working on the engine to be smart enough to not need it.
2020-07-30 18:45:55 +02:00
Pieter-Jan Briers
d3786df4bb Analyzer for the lidgren tests aswell. 2020-07-30 18:41:37 +02:00
Pieter-Jan Briers
2fc6614118 Add NUnit.Analyzers analyzer
Caught numerous cases of expected/actual being mixed and even a few broken test cases in content.
2020-07-30 18:38:17 +02:00
Pieter-Jan Briers
907db466c9 Update NetSerializer submodule for optimizations. 2020-07-30 15:06:45 +02:00
Pieter-Jan Briers
6a62b618dc More NetSerializer unit tests. 2020-07-30 15:06:45 +02:00
Pieter-Jan Briers
3cc092f9ee Make RobustMappedStringSerializer use NetSerializer's string serialization code again.
It's much more efficient, especially after more optimizations I just made to it.
2020-07-30 15:06:45 +02:00
Pieter-Jan Briers
380432a1f1 Optimize IRobustSerializer usages throughout the code.
Mark some classes as sealed where possible to remove type tags.
Re-order GameStateMapData.GridCreationDatum to reduce memory usage.
Use MemoryStream.TryGetBuffer instead of .ToArray() all over the place to cut out allocations.
Use VariableInt32s for serialized buffer sizes.
Use IRobustSerializer.SerializeDirect<T> where possible.
2020-07-30 15:06:45 +02:00
Pieter-Jan Briers
028453acee Add SerializeDirect/DeserializeDirect to IRobustSerializer.
This matches the NetSerializer API to skip initial type IDs which is a bit more efficient.

Also made RobustSerializer thread safe.
2020-07-30 15:06:45 +02:00
Pieter-Jan Briers
0b302b5171 Move a Span<byte> -> ReadOnlySpan<byte> in NetBuffer.Write.cs 2020-07-30 15:06:45 +02:00
DrSmugleaf
011a06a7d8 Fix za buildo (#1202) 2020-07-30 13:46:17 +02:00
Acruid
3f5321853a Removed obsolete ScreenToWorld methods from EyeManager. 2020-07-29 16:54:01 -07:00
Acruid
350e05c152 Adds new functions to IComponentManager that can efficiently query for all entities with a set of components. 2020-07-29 15:48:32 -07:00
Acruid
0bf451d5d4 Turns out TransformComponent already has the matrix available to use. 2020-07-29 14:27:20 -07:00
Acruid
b8e9e3634b Grid rendering can now render rotated grids. 2020-07-29 12:05:09 -07:00
DrSmugleaf
1de41531ce Fix casing on physics and collidable data fields (#1197) 2020-07-29 14:43:18 +02:00
Acruid
876d528578 Had to optimize the physics so that the client runs on my laptop. 2020-07-29 00:47:47 -07:00
Pieter-Jan Briers
3648f43f5c Include NetSerializer as a submodule, add List<T> serializer. (#1195)
* Include NetSerializer as a submodule.

* NetSerializer list serializer.

* Update Actions workflows to handle the new submodule.

* Whoops
2020-07-28 18:56:20 -07:00
py01
708e546446 CollidableComponent Anchored serialization (#1196)
Co-authored-by: py01 <pyronetics01@gmail.com>
2020-07-28 18:43:09 -07:00
Pieter-Jan Briers
e5ddc4f654 Move light intersection check earlier, slight optimization.
Not sure why it wasn't like this in the first place.
2020-07-29 02:10:04 +02:00
Pieter-Jan Briers
c482253b9d Clyde debug stats for light count. 2020-07-29 02:06:39 +02:00
Moses
27fccbe74c 1513 Erase mode button toggle (#1194) 2020-07-28 14:12:29 -07:00
Pieter-Jan Briers
c945c2abad Mark EntityEventArgs as serializable.
Internal NetSerializer assertions need this.
2020-07-28 02:31:12 +02:00
Pieter-Jan Briers
b9573d8c00 Fixes container occlusion not updating if container manager is deleted.
Fixes space-wizards/space-station-14/issues/1352
2020-07-27 16:30:25 +02:00
Pieter-Jan Briers
406e5277a6 Integration testing improvements.
Run Update in Integration game loop.
Ability to load extra prototypes from a string.
2020-07-26 14:07:24 +02:00
L.E.D
16d50f3ecf Container light occlusion (#967)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-07-26 13:28:25 +02:00
Víctor Aguilera Puerto
d5e422f34e Debug coordinates panel now displays actual entity transform position 2020-07-26 03:16:10 +02:00
Pieter-Jan Briers
a3d250a5c4 Allow YamlObjectSerializer to read/write immutable interface collections. 2020-07-26 01:35:43 +02:00
ShadowCommander
30108cf992 Refactor DetachParent (#1188) 2020-07-25 17:04:14 +02:00
Exp
d2d248a175 Fixed Pitch Bend not working correctly (#1190) 2020-07-24 14:39:48 +02:00
DrSmugleaf
40a8dae236 Allow one VirtualController in CollidableComponent per individual type (#1189)
* Replace single controller with a dictionary

* Actually initialize the controller dictionary

* Fix not upgrading old physics controllers

* Return controller when adding it in CollidableComponent

* Make GetOrCreate name consistent

* Add updating linear velocity depending on controllers

* Address reviews

* Update Robust.Shared/Physics/VirtualController.cs

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>

* Add missing physics component methods

* Make method names consistent with the rest of the project

* Add documentation to controller manipulation methods

* Add another method for controller manipulation

* Add SetController method

* Add stop method

* Add stop method to controllers

* Add bool return type to controller stopping and GetControllers method

* Fix physics stop return type not being bool

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-07-23 18:32:45 +02:00
Acruid
52da9b48d7 Marks the 'Default Grid' API methods as Obsolete, in preparation for their removal. 2020-07-22 15:04:41 -07:00
Acruid
8475c1ae4b Moves all of the PhysicsComponent data to the CollidableComponent, and marks the PhysicsComponent as obsolete. 2020-07-21 23:36:42 -07:00
Pieter-Jan Briers
0297464af5 Fix MapID assignment in transform init. 2020-07-22 01:51:17 +02:00
Pieter-Jan Briers
6e35b37e0f Fix stretching bugs on odd viewport sizes. 2020-07-21 00:59:52 +02:00
Pieter-Jan Briers
aa596610de Adds initialization assert to AddComponent. 2020-07-21 00:14:08 +02:00
Pieter-Jan Briers
bbbaef5da4 Fix integration tests.
They weren't pumping networking anymore because Acruid moved it to Input.
2020-07-20 12:12:56 +02:00
Pieter-Jan Briers
e68c5b47e7 Remove Fody and ImageSharp hack.
They have a public method for this...
2020-07-20 01:09:06 +02:00
Pieter-Jan Briers
808bbeb71c Remove CollectionExtensions.Deconstruct
Long live KeyValuePair<,>.Deconstruct
2020-07-20 01:03:30 +02:00
Pieter-Jan Briers
449ed4ad7c Don't detach from console.
This was a dumb idea.
2020-07-20 01:02:06 +02:00
Pieter-Jan Briers
f6e900e6fd Don't run Prometheus metrics on the client. 2020-07-20 01:01:35 +02:00
Acruid
5e448f20c0 Move parts of the simulation update back into engine, from Content's StateBase.
Allow content to push modal windows in the UI framework.
The MenuBar now closes it's MenuButton frame when you select one of the buttons.
Modal controls on the stack now actually block input from the rest of the UI.
Adds the `scene` concommand for instantly switching between game states (scenes).
2020-07-19 12:31:13 -07:00
DrSmugleaf
ede9795ba6 Fix nullable error (#1185) 2020-07-19 12:38:41 +02:00
Acruid
64bb519bce Adds PhysBody sleep visualization to the Collidable overlay. 2020-07-19 02:34:19 -07:00
Acruid
4ed044ddb4 Added an interface for PhysicsComponent.
Converted everything to use collision and physics component interfaces.
2020-07-19 00:32:06 -07:00
Pieter-Jan Briers
00674d5624 Clean Clyde state at start of frame to make it more robust. 2020-07-18 23:10:32 +02:00
Pieter-Jan Briers
42b6ee9740 Fix BeforeUI screenshots. 2020-07-18 16:10:40 +02:00
Pieter-Jan Briers
abdc5418e2 Clyde object resource management.
Objects now use IDisposable().
Finalizers.
2020-07-18 16:01:24 +02:00
Exp
eeabe9af02 Remember Window Size & Pos when switching to/from fullscreen (#1181) 2020-07-17 10:37:55 +02:00
Pieter-Jan Briers
d1d610cce6 Add a TODO 2020-07-16 16:00:31 +02:00
Pieter-Jan Briers
9bcb892215 Make Eye a public property on EyeComponent. 2020-07-16 16:00:31 +02:00
Pieter-Jan Briers
7ea6b9c470 Minor cleanup and optimizations inside Clyde. 2020-07-16 16:00:31 +02:00
Pieter-Jan Briers
855e548651 Refactor Clyde internals so multiple viewports is possible. 2020-07-16 16:00:31 +02:00
Víctor Aguilera Puerto
4b7a5b4e93 Added method to get a RSI state frame at a specific second. 2020-07-15 14:29:19 +02:00
Exp
cca0b81bc6 Added Approximation Parameter to GetCollidingEntities (#1183) 2020-07-15 12:36:37 +02:00
Víctor Aguilera Puerto
fbaf3297b9 Fix compile 2020-07-15 11:44:36 +02:00
Víctor Aguilera Puerto
21d18731ba Overlay FrameUpdate is now protected internal. 2020-07-14 23:44:16 +02:00
Víctor Aguilera Puerto
ce89b7c93d Overlay's FrameUpdate is now public. 2020-07-14 23:40:44 +02:00
Pieter-Jan Briers
9e7b50a12e Fix nullability. 2020-07-13 16:29:03 +02:00
Pieter-Jan Briers
b7e224a56f Moving a ton of rendering code around and it somehow still works somewhat. 2020-07-13 16:27:43 +02:00
Pieter-Jan Briers
16ba90a654 Fix nullability error. 2020-07-13 02:02:14 +02:00
Pieter-Jan Briers
df4e8e3175 Please actually fix the server crashes thanks. 2020-07-13 01:56:42 +02:00
Pieter-Jan Briers
a5f6363219 Fix logging crash hopefully. 2020-07-13 01:23:10 +02:00
Pieter-Jan Briers
bd699eeb57 Removed _queuedSpace from Clyde internals. 2020-07-12 19:14:29 +02:00
DrSmugleaf
40f9381b7f Make IMapGridComponent public instead of internal (#1179) 2020-07-11 17:50:14 -07:00
Pieter-Jan Briers
70dc286e4f How about you don't commit the temporary profiling changes? 2020-07-11 18:48:14 +02:00
Pieter-Jan Briers
285b6914e2 Fix NetManager.ServerSendToAll sending to connections that are in the middle of their handshake.
I took the liberty to refactor it a bit internally so we can keep up-to-date copies of the NetPeer connection and channels lists per-peer. This allows us to avoid expensive copying allocations (Lidgren does not expose NetPeer.Connections without allocating due to thread safety)
2020-07-11 18:29:20 +02:00
Hugal31
63720cd034 Feature/the macro (#1165)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-07-11 15:03:28 +02:00
Pieter-Jan Briers
f879ced75e Fix exception from client shutdown from logging inside Dispose() 2020-07-11 14:39:58 +02:00
Pieter-Jan Briers
93fcb0df9b Move back to per-component-type-dictionaries for component storage.
It's much faster than the single dictionary approach.
2020-07-11 13:15:44 +02:00
ShadowCommander
8e39de77f1 Fix GridPosition set breaking when value.GridID == GridId.Invalid (#1178) 2020-07-11 02:38:36 -07:00
ike709
6e3b32ed07 Adds logout command, tweaks login (#1174) 2020-07-10 21:04:33 +02:00
DrSmugleaf
8cd13787ea Fix collection modified during iteration (#1177) 2020-07-10 21:03:40 +02:00
Pieter-Jan Briers
a2617312d9 Use Serilog internally for logging, add Grafana Loki log handler. 2020-07-10 20:55:31 +02:00
Pieter-Jan Briers
25eb83d3c3 Mute spammy debug log in PVS. 2020-07-09 15:51:19 +02:00
Pieter-Jan Briers
bec9639554 Optimize PVS a little bit. 2020-07-09 02:56:07 +02:00
Pieter-Jan Briers
8f590a7ba9 DependencyCollection.RegisterInstance no longer caches injectors.
Small optimization.
2020-07-09 02:55:04 +02:00
metalgearsloth
d1ee8775f4 Fix pathfinding for entity deletions (#1173)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-07-08 14:00:48 +02:00
Pieter-Jan Briers
6088df4018 Make LineEdit cull rendering on the left of its bounding box aswell.
Fixes https://github.com/space-wizards/space-station-14/issues/1300, although realistically this is more an optimization that happens to fix the bug.
2020-07-08 03:14:38 +02:00
Pieter-Jan Briers
c2ce37517f Mouse wheel scrolling for Tree control.
Fixes https://github.com/space-wizards/space-station-14/issues/1309
2020-07-08 02:50:27 +02:00
Pieter-Jan Briers
0a88f32206 Fix KeyDowns not prioritizing mouse focus.
This caused https://github.com/space-wizards/space-station-14/issues/1302.

The ChatBox focuses the LineEdit in KeyDown. This then causes the next key down, UIClick, to go to the LineEdit (it's keyboard focused now). The key up however is fired on the chatbox because keyups did prioritize mouse focus. So the LineEdit gets stuck thinking you have the mouse held down.
2020-07-08 02:44:59 +02:00
Pieter-Jan Briers
fc73f88282 Hitting ~ while console is selected now closes it again.
How did this take me this long to fix.
2020-07-08 01:53:11 +02:00
AJCM-git
afa0eb8ada Changing some paths (#1158)
* first commit

* Merging master

* Path changes

* what even is this

* MidiCustom
2020-07-07 19:15:39 +02:00
Víctor Aguilera Puerto
578ae1cf9e Add percentage of intersection to Box2 (#1169) 2020-07-07 18:13:51 +02:00
Pieter-Jan Briers
4b3be2db3d ACTUALLY remove low res lights biasing hack. 2020-07-07 13:26:35 +02:00
Pieter-Jan Briers
8a35696716 Remove low res lights biasing hack. 2020-07-07 13:20:18 +02:00
Pieter-Jan Briers
e9de95be31 Fix replication of new components with interp enabled. 2020-07-07 12:25:12 +02:00
Víctor Aguilera Puerto
8619c2a7c9 Add Hard property to ICollidableComponent 2020-07-07 12:03:05 +02:00
Víctor Aguilera Puerto
bb46b49d30 Fix hard collidable property not being sent to the client 2020-07-07 11:58:24 +02:00
Pieter-Jan Briers
cc9391c029 Probably fix parallel PVS crashes. 2020-07-06 23:38:15 +02:00
Pieter-Jan Briers
ded0b6b710 PlayerCommandStates.SetState 2020-07-06 23:22:12 +02:00
Pieter-Jan Briers
9e5374ac86 Assert that messages have been registerd in integration tests. 2020-07-06 21:24:03 +02:00
SoulSloth
e15b5ad3d1 Added User Input Validation For Most Debug Commands (#1167) 2020-07-06 21:23:26 +02:00
chairbender
437bf58e7b Input Handling + other cleanups to support click drag functionality (#1132)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-07-06 21:21:13 +02:00
Pieter-Jan Briers
7e6a6b085b Fix MsgServerInfoReq not being registered client side. 2020-07-06 19:43:26 +02:00
Pieter-Jan Briers
46ff3715f8 Fix possible race condition with CreateNetMessage<T> and threads. 2020-07-06 19:15:06 +02:00
DrSmugleaf
265c249708 Fix physics anchored status not being synced to the client (#1168) 2020-07-06 15:44:09 +02:00
Acruid
8b5e5b7b91 Adds Events to IEntitySystemManager for when a system is loaded or unloaded into the manager. 2020-07-04 16:16:54 -07:00
Pieter-Jan Briers
af4c920606 Don't lerp transforms on teleports/parent changes. 2020-07-04 00:35:40 +02:00
Pieter-Jan Briers
8d89a6af05 Add some VV attributes to containers. 2020-07-04 00:35:40 +02:00
DrSmugleaf
71c3efc274 Fix client crashes when invalid arguments are used with the gridtc command (#1164) 2020-07-03 23:19:08 +02:00
Pieter-Jan Briers
87a57c18ca Fix exception on reconnect. 2020-07-03 16:58:07 +02:00
Pieter-Jan Briers
0720d4d39c Fix deleted entities staying in render trees.
Alright that one was pretty obvious in hindsight.
2020-07-03 01:08:30 +02:00
Pieter-Jan Briers
c8560c9445 Fix physics shapes not setting their parent collidable dirty. 2020-07-02 21:18:50 +02:00
Pieter-Jan Briers
41d1aa2a82 Fix some incorrect nullability attributes in input manager. 2020-07-02 20:47:07 +02:00
Jackson Lewis
2d7192d79d Add Hard property to collidables and fix airlock issues (#1078)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-07-02 13:35:58 +02:00
Acruid
99933499b7 Merged Client and Server PhysicsComponent (#1163) 2020-07-02 09:34:16 +02:00
Tyler Young
d9fb7d04ca Enable freezable sets in unique index implementations (#1161) 2020-07-01 16:37:25 +02:00
ShadowCommander
6c2157c10f Change ScrollContainer ScrollBars to not affect layout when not visible (#1162) 2020-07-01 16:36:53 +02:00
Pieter-Jan Briers
830f5843b5 Delete grid entity BEFORE removing the grid.
If the gridentity is deleted after then ALL those entities suddenly have an invalid Grid ID and this is a massive problem.
2020-07-01 02:26:54 +02:00
Pieter-Jan Briers
466ce76ca9 Fix nullspace issues with RenderingTreeSystem 2020-07-01 02:24:20 +02:00
Pieter-Jan Briers
9da67e6a66 Fix compiler warnings. 2020-06-30 19:27:25 +02:00
py01
650033a184 Event for changing server PhysicsComponent Anchored (#1160)
Co-authored-by: py01 <pyronetics01@gmail.com>
2020-06-30 18:44:03 +02:00
Pieter-Jan Briers
2296c95e7c PVS optimizations. 2020-06-30 18:34:17 +02:00
Pieter-Jan Briers
2af0d9df55 Optimizations to physics system.
Nothing major, just picking low hanging fruit and improving code quality around the place.
2020-06-30 15:13:51 +02:00
Pieter-Jan Briers
1087e4ce69 Remove some unnecessary interface calls. 2020-06-29 20:44:44 +02:00
Pieter-Jan Briers
59911bee28 Good job me. 2020-06-29 20:23:18 +02:00
Pieter-Jan Briers
daa5a34413 Guess we're doing render trees for lights and occluders aswell. 2020-06-29 20:23:08 +02:00
Pieter-Jan Briers
cf47525237 Fix UTF-8 output AGAIN. 2020-06-29 18:04:26 +02:00
Pieter-Jan Briers
16b4262486 Remove dead code. 2020-06-29 16:19:11 +02:00
Pieter-Jan Briers
b72b0e5984 Use a DynamicTree for sprite finding.
Significantly improves client CPU usage.
2020-06-29 16:18:11 +02:00
Pieter-Jan Briers
334d319cda Slight physics optimizations.
Removal of interface calls and some LINQ.
2020-06-29 16:13:54 +02:00
Pieter-Jan Briers
1cdaed3b54 Allow EntitySystems to handle struct events. 2020-06-29 16:10:54 +02:00
Pieter-Jan Briers
a40d89dd3e Optimize TransformSystem.
Now keeps a list of actively lerping transforms instead of iterating every transform every tick.

Yeah it doesn't even show up in profiles anymore instead of taking like 8% of CPU time.
2020-06-28 00:41:48 +02:00
Pieter-Jan Briers
6742290e91 Fix VVing enumerables. 2020-06-26 20:28:12 +02:00
Pieter-Jan Briers
75b63f2645 Enable interp by default. 2020-06-26 16:16:52 +02:00
Pieter-Jan Briers
b71899f830 Fix RobustTaskScheduler with non-long-running-tasks. 2020-06-26 02:37:12 +02:00
Pieter-Jan Briers
31c964b9d7 Fix IPv6 sockets on Linux.
By removing Q's NativeSockets layer and just using byte[] again.

There's no performance loss because byte[] was already the only thing used.
2020-06-26 02:37:12 +02:00
Tyler Young
9d03edee40 Logging Tweaks (#1156) 2020-06-25 22:00:45 +02:00
Pieter-Jan Briers
1a7cc344e2 Optimize TransformComponent component state handling:
1. Don't resolve Parent in GetComponentState
2. Don't try to AttachParent unless parent actually changed.
2020-06-25 18:17:25 +02:00
Tyler Young
08e9caf71d Remove Task Scheduler Naming of Long Running Threads (#1155) 2020-06-25 18:16:41 +02:00
Pieter-Jan Briers
96e94b3dbd Fixes for ConsoleLogHandler
Actually respects terminal encoding.

Doesn't do ANSI characters if unsupported (Windows) or redirected.

Uses 4-bit color codes instead of RGB codes.

More optimal outputting of ANSI escape codes. It's const all the way down.
2020-06-25 18:16:16 +02:00
Tyler Young
faacd45eb4 Protect IgnoresAccessChecksTo, Add Task Scheduler Context, Lock on Console Log Flushing (#1153) 2020-06-25 18:00:00 +02:00
Pieter-Jan Briers
f77fdbced6 Remove finalizer from Control.
We aren't used Godot anymore so no need for this.
2020-06-25 16:29:03 +02:00
Pieter-Jan Briers
99d900b68c I am good at copy paste. 2020-06-25 13:59:10 +02:00
Pieter-Jan Briers
564e219504 Silence string serializer. 2020-06-25 02:28:12 +02:00
Pieter-Jan Briers
ff68a70aef More lidgren stats exposed to prometheus. 2020-06-25 02:27:20 +02:00
Pieter-Jan Briers
f71f2821d1 Fix latency simulation. 2020-06-25 02:27:19 +02:00
Tyler Young
e693d3ded7 Buffered VT ANSI Logging, Server Off Console Thread, Log Unhandled Errors (#1152) 2020-06-25 01:43:09 +02:00
Tyler Young
d7e98be313 Various Fixes and Diagnostics (#1151) 2020-06-24 23:52:22 +02:00
Tyler Young
ba3bf605c9 Reduce Physics Max Solver Iterations, Simulation Respected (#1150)
reduce max solver iterations
2020-06-24 23:43:07 +02:00
Tyler Young
ec938e7d33 Better Missing MetaDataComponent Error (#1149) 2020-06-24 23:28:14 +02:00
Pieter-Jan Briers
41f1dd3fa0 Hopefully fix parallel game states 2020-06-24 22:55:59 +02:00
Pieter-Jan Briers
2bd6b20137 HOPEFULLY fix parallel PVS. 2020-06-24 21:40:44 +02:00
Pieter-Jan Briers
544c728a34 sudo command 2020-06-24 20:48:46 +02:00
Pieter-Jan Briers
31fb65bcb9 Movement prediction work. (#1144)
* Fix client-side input system not sending sequence numbers for input messages.

This caused message ordering issues and keys getting stuck down.

* Make sure EyeUpdateSystem runs after physics.

* IGameTiming.TickFraction helper.

* Subtick data for input commands.

* Literally a unit test to verify that I wasn't going insane while debugging input message ordering issues.

* More prediction logs behind net.predict.

* Move physics to shared and run it on the client.

* Synchronize grid gravity.

* Fix ResetPredictedEntities crash when entities get deleted server-side.

* Fix CollidableComponent setters not calling Dirty()

* Fix going into space while predicting.

* Watch window uses history line edit.

* Fix unpredicted objects stuck-jittering.

* VV tags for interp vars on transform.

* Fix 0 mass objects on client.

* Fix friction calculations being TPS dependent.

* Reset predict flag on handelComponentState
2020-06-24 20:47:20 +02:00
ShadowCommander
1a580d226c Implement MultipleTypeEntityQuery (#1146)
* Implement MultipleTypeEntityQuery

* Add EntityQuery to make the MultipleTypeEntityQuery faster
2020-06-24 10:38:26 -07:00
ShadowCommander
71e2344a73 Implement HostLogin command (#1147)
* Implement HostLogin command

* Fix Robust.Server/server_config.toml

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-06-24 19:12:22 +02:00
Pieter-Jan Briers
14fea1812d Scripting watch window 2020-06-24 15:25:11 +02:00
Tyler Young
4650dc2c49 ComponentManager Rework (#1143)
* rework ComponentManager

create indexing solution, UniqueIndex

split out ComponentEventArgs, add sealed variants

fix up documentation

fix terrible crap

make benchmark work

* woops, ordered enumerables are already a copy

* naming

* clean up comments

* nullable enable

* add some doc comments to unique index

* perf tweaks

add UniqueIndexHkm for high key mutability

extract internal interface mostly for documentation

add nullability support and constraints

* fix doc comment for UniqueIndexHkm

* make PVS threaded

* remove redundant member declarations in interface

* fix grid loss crap on client shutdown

* fix nullability warning when retrieving from always constructed threadlocal

* add comment explaining chan == null check

remove inParallel parameter
2020-06-24 11:59:56 +02:00
Tyler Young
faff0797bf Make Lidgren Use Spans & Shared Pool (#1140)
* make lidgren use spans everywhere where it can

convert custom pooling to shared array pool impl

add unit tests for read/write

add native socket extensions to socket so we can legit pass spans for SendTo/ReceiveFrom

bump version in lidgren csproj

replace some random "% 8" w/ "& 7"

more minor nullability hacks to fix static analysis complaints

made receiving packets use span

minor native sockets refactor to use pinvoke

add read/write constrained/prealloc'd bit stream impl to lidgren and update usages

fixed missing stream cleanup

remove outstanding stream cleanup since it refs buffer thru the class, can't read some other buf

apply suggestions from code review

remove unsafe cruft

* add tests to gh actions

* make stats use interpolation in tostring and remove m_bytesAllocated since it's all in the shared pool now

* this pr still open so fuck it

stats, human readability, faster BitsToHold methods

* add api compatible version of ReadBytes

* rename ReadOnlyStreamWrapper -> ReadOnlyWrapperStream

rename WriteOnlyStreamWrapper -> WriteOnlyWrapperStream

add AppendViaStream, AppenderStream impl

add and update documentation on read/write bytes methods

also fix some goofs
2020-06-24 04:09:20 +02:00
chairbender
2558201ae4 implement dragging of split in split containers (#1141) 2020-06-22 18:50:34 +02:00
Tyler Young
c997d7e3b6 Dynamically Manage Collision Solver Iterations (#1139)
modulate solver iterations dynamically depending on tps
2020-06-22 12:33:08 +02:00
Clyybber
2b6ed4852d Cleanup occlusion (#1138) 2020-06-22 12:32:29 +02:00
Tyler Young
368f6482e8 Provide fallback for Creative EFX OpenAL Extension in Clyde.Audio (#1137)
provide fallback for mac if it doesn't exist
2020-06-19 21:25:19 +02:00
Vince
7dd0a668d5 Changed "Run" to "Walk" in code (#1136) 2020-06-19 15:14:18 +02:00
Pieter-Jan Briers
8e4ac24840 Re-enable prediction logging but put it behind a cvar. 2020-06-19 00:18:59 +02:00
Pieter-Jan Briers
77b7d4f683 Move transform interp to an entity system. 2020-06-19 00:18:59 +02:00
Pieter-Jan Briers
67efd69679 Add explicit update dependency specification between entity systems.
This allows a system to say "I want to update after this other system does".

Based on @chairbender's work with the input binding stuff.
2020-06-19 00:18:59 +02:00
Víctor Aguilera Puerto
185e03b8a3 EntityManager's GetEntity throws again, fixes doc 2020-06-18 15:29:54 +02:00
Víctor Aguilera Puerto
4a11a5086e EntityManager's GetEntity returns null if entity doesn't exist 2020-06-18 15:23:59 +02:00
Tyler Young
9cbdd1058c Use CannyFastMath & Update Some Packages (#1130)
update a bunch of packages and use JetBrains.Annotations as private asset as needed

mark some hot math methods agg inline to benefit from loop opts

use FMA for interp

use canny min/max/clamp

make Quaternion NormalizeAngle fixed time and faster

clean up YamlDotNet references
2020-06-18 02:25:36 +02:00
Pieter-Jan Briers
af249f80c8 Improved click detection supporting features: (#1133)
* Improved click detection supporting features:

Clickable removed from engine
Texture/RSI load hooks for content
New sprite layer API

* Fix tests.
2020-06-18 02:25:02 +02:00
Pieter-Jan Briers
6dba85e6dd Use Robust.Shared.AuthLib. 2020-06-18 02:19:14 +02:00
Acruid
bc2d4c1c92 Fixes a bug where the EntitySystem event proxy was using the wrong function overload for IEventBus.RaiseEvent(). 2020-06-17 17:05:48 -07:00
Pieter-Jan Briers
2a93cb0c41 Adds helpers to make constructing style rules much cleaner. 2020-06-17 15:32:22 +02:00
Pieter-Jan Briers
52833e23c3 Fix URI opening on Windows and remove linux/mac impls.
Because .NET can directly open URLs with Process.Start apparently.
2020-06-17 02:20:58 +02:00
Pieter-Jan Briers
66f112f9d9 Add system for reporting open source licenses for dependencies. 2020-06-14 02:27:11 +02:00
Pieter-Jan Briers
65c7e07d9b Adds ReadAllText convenience methods to IResourceManager. 2020-06-14 02:27:11 +02:00
Tyler Young
9662d52f90 Shared String Dictionary ctd. (#1126) 2020-06-13 04:09:48 +02:00
Pieter-Jan Briers
15ec0e7bd9 Adds missing Lidgren license. 2020-06-13 03:10:18 +02:00
Pieter-Jan Briers
36bda1cd2f Remove SharpZipLib and System.ValueTuple dependencies 2020-06-13 03:10:17 +02:00
Tyler Young
47f307dd2a Upgrades SixLabors.ImageSharp (#1128)
adds InlineIl.Fody for fast access to image backing buffers
2020-06-13 03:08:29 +02:00
Pieter-Jan Briers
b3d4f55f28 Fix ResourcePath.ChangeSeparator for rooted paths. 2020-06-12 22:51:25 +02:00
Pieter-Jan Briers
919174056a Fix to-client entity messages getting dispatched in the incorrect order. 2020-06-12 18:25:05 +02:00
Pieter-Jan Briers
aaa09881cb Enable NRTs for unit tests. 2020-06-12 17:11:32 +02:00
Pieter-Jan Briers
b1ab4a61f8 Make sure integration tests get shut down on test tear down. 2020-06-12 15:16:03 +02:00
Pieter-Jan Briers
9b7b8023f2 Treat nullability warnings as errors in CI. 2020-06-12 14:22:58 +02:00
Pieter-Jan Briers
c5e1fbcbab Verbose logging on test. 2020-06-12 14:07:08 +02:00
Pieter-Jan Briers
02e41a8ed6 Jesus christ I can't even copy paste right. 2020-06-12 14:01:05 +02:00
Pieter-Jan Briers
e8c0ab52f5 Actually run integration tests. 2020-06-12 14:00:25 +02:00
Pieter-Jan Briers
6674be3adc Client NRTs (#1121) 2020-06-12 12:57:39 +02:00
Víctor Aguilera Puerto
4d93b0c533 Sound track in animations can now take a function that returns an AudioParam (#1125) 2020-06-12 12:47:34 +02:00
Pieter-Jan Briers
28b3cd5a52 Fix predicted events not re-firing on first sender tick. 2020-06-12 12:42:05 +02:00
Pieter-Jan Briers
ca1597d952 Add some convenience helpers for integration testing. 2020-06-12 12:42:05 +02:00
Pieter-Jan Briers
afb0624a2b Fix DebugTimePanel to report prediction size correctly.
It was not taking into the account that CurTick increments after the mainloop runs tick meaning that it was offset by one.
2020-06-12 12:42:05 +02:00
Tyler Young
0d52def877 Have RobustSerializer use a shared string dictionary (#1117)
* implements shared string dictionary and handshake from net-code-2

* fix unit test

switch to szr sawmill

* try to silence some warnings around ZipEntry

* rebase and use system zip instead of icsharplib

fix rebase artifacts

* Update Robust.Shared/Interfaces/GameObjects/IComponentFactory.cs

* Update Robust.Shared/Serialization/RobustSerializer.MappedStringSerializer.cs

* Update Robust.Shared/Serialization/RobustSerializer.MappedStringSerializer.cs

* Apply suggestions from code review

* Apply suggestions from code review

* Update Robust.Shared/Serialization/RobustSerializer.cs

* since no longer gathering from paths, make string splitting more robust

* make string gathering ignore strings under 4 chars long

make string gathering yet more robust

* add limit to size of mapped strings

* add more string data to feed into shared string dictionary from YAML files

add JSON importer but don't parse RSI metadata yet

fix typo that breaks nulls in MappedStringSerializer

minor refactoring

make string splitting more robust

add WriteUnsignedInt / ReadUnsignedInt for validating WriteCompressedUnsignedInt / ReadCompressedUnsignedInt aren't bogus

* comment out some log statements

* minor refactor, reorder logging

add null check due to smart typing NRT checks

* Add doc comments, readability improvements to MappedStringSerializer

The protocol, handshake, and internal logic are now more documented.

The main area that could still be improved is the documentation of how
the cache system works, but the code is readable enough for now that it
isn't immediately necessary.

* add documentation, organization

* update some more doc comments

* add flows to doc comment for NetworkInitialize

* more documentation and organization

* more docs

* instead of retrieving INetManager by IoC, assign when NetworkInitialize is invoked

* "document" the regex

* Update Robust.Shared/Network/NetManager.cs

* add missing check for LockMappedStrings

* Update Robust.Shared/Serialization/RobustSerializer.MappedStringSerializer.cs

Co-authored-by: ComicIronic <comicironic@gmail.com>

* change to warning instead of throw for unlocked string mapping

Co-authored-by: ComicIronic <comicironic@gmail.com>
2020-06-12 04:09:55 +02:00
Tyler Young
70100ec9d1 add reset of shader to UserInterfaceManager _render method after drawing a control (#1124) 2020-06-11 22:50:33 +02:00
Pieter-Jan Briers
edbe2839b6 Use GetProcAddress for DebugMessageCallback in OpenGL. 2020-06-10 15:13:48 +02:00
Pieter-Jan Briers
8f63ee481e Make sure CurTick increases AFTER ticks in integration tests.
For consistency with the real main loop.
2020-06-10 04:59:50 +02:00
Pieter-Jan Briers
1cf613a076 Free 10% PVS perf improvement. 2020-06-10 04:38:54 +02:00
Pieter-Jan Briers
550e295189 EntitySystemManager API to load extra entity system types. 2020-06-10 01:54:09 +02:00
Acruid
fbeae98025 Made the 'group' concommand actually work. 2020-06-09 12:34:51 -07:00
Acruid
cafe99a0e2 Adds exception tolerance to ECS system Update and FrameUpdate. Previously an exception thrown in FrameUpdate would completely break rendering, and an exception thrown in update would block all other ECS systems after it being ran. 2020-06-09 12:34:50 -07:00
Pieter-Jan Briers
6a2f8f2767 Fix tree control jittering. 2020-06-09 21:28:02 +02:00
Pieter-Jan Briers
0d3cd41382 Enable NRTs on Robust.Server (#1118) 2020-06-09 14:18:29 +02:00
Pieter-Jan Briers
b2eff5d5eb Improve & fix entity creation tick clearing.
Tick clearing is now done in all entity constructors on the server, and components added during ExposeData like ContainerManager don't blow up on it anymore.
2020-06-09 14:11:31 +02:00
Pieter-Jan Briers
76b0779563 More convenient system for integration tests to override CVars. 2020-06-09 14:11:30 +02:00
Víctor Aguilera Puerto
251f0422b6 Add distance to AudioSystem (#1079)
* Add distance to AudioSystem

* Fix warning

* Rewrite distance thing.

* Better unchecked

* Whoops.

* Raise default distance to 25
2020-06-09 14:09:56 +02:00
ComicIronic
a284e9f244 Add ScreenToMap overload taking ScreenCoordinates (#1120)
This was a small hole in the API, no real new functionality.
2020-06-09 13:56:52 +02:00
Pieter-Jan Briers
3cbfef8b07 Yep it's definitely late *checks clock* oh god. 2020-06-09 03:49:09 +02:00
Pieter-Jan Briers
bdab4bc6c9 Why WOULD I run my own tests before pushing? 2020-06-09 03:47:04 +02:00
Pieter-Jan Briers
73618f6bb2 Fix map loading and add map loading unit test. 2020-06-09 03:43:33 +02:00
Pieter-Jan Briers
be1ceeb2db Add testing convenience helper to mount strings as files in the VFS. 2020-06-09 03:43:33 +02:00
Pieter-Jan Briers
c9d2b9687f Fix SingleStreamLoader.FindFiles. 2020-06-09 03:43:33 +02:00
Pieter-Jan Briers
1268e03770 Update test-content.yml 2020-06-09 03:02:10 +02:00
Pieter-Jan Briers
b502e92c3a Create test-content.yml 2020-06-09 02:59:47 +02:00
Tyler Young
5c8545c396 Revert "Virtualize all NetIDs to reduce network traffic" (#1119)
This reverts commit d776476542.
2020-06-09 00:34:37 +02:00
Pieter-Jan Briers
7f406aa16c Fix natives copy probably. 2020-06-09 00:32:08 +02:00
Pieter-Jan Briers
289938dbd1 Refactor PackLoader.
Use System.IO.Compression instead of SharpZipLib.
Unit tests.
Fixes.
2020-06-08 23:58:32 +02:00
Pieter-Jan Briers
3459e5fd0b Remove explicit x64 platform target to fix ARM64 builds. 2020-06-08 23:36:08 +02:00
Pieter-Jan Briers
b51d22216e Fix a compiler warning. 2020-06-08 14:43:57 +02:00
Pieter-Jan Briers
aec9c5e66d Clear IoC on RobustUnitTest TearDown to hopefully provide better test isolation. 2020-06-08 14:36:18 +02:00
Pieter-Jan Briers
9a637a0632 Fix ComponentManager_Tests on release mode. 2020-06-08 14:35:50 +02:00
Pieter-Jan Briers
b3f8e12739 Update .NET Core SDK version to latest on Actions. 2020-06-08 14:03:40 +02:00
Clyybber
71b06c0791 Placement improvements (#1105) 2020-06-08 13:51:22 +02:00
ComicIronic
9ab3f13f2d Make AddComponent load default DataField values (#1112)
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2020-06-08 13:51:08 +02:00
Tyler Young
d776476542 Virtualize all NetIDs to reduce network traffic (#1116) 2020-06-08 13:38:08 +02:00
metalgearsloth
865c04b264 Add collidable events back in (#1115)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-06-08 13:29:16 +02:00
Pieter-Jan Briers
ec0f4b35f7 Enable nullable reference types on Robust.Shared and fix all warnings. (#1109) 2020-06-08 01:13:01 +02:00
Acruid
12ea903c98 Map Loading (#1110) 2020-06-08 00:56:55 +02:00
ComicIronic
d631048c1e Remove ScreenToWorld (#1114) 2020-06-08 00:41:59 +02:00
Pieter-Jan Briers
dd0cb9f216 Prometheus metrics server.
Thanks to Redline for starting work on this and helping me out on Discord.
2020-06-08 00:12:23 +02:00
ComicIronic
15432bf8a7 Fix client CurTime jumps (#1113)
This fixes the issue where CurTime on the client would sometimes jump by
massive values. It was caused by an underflow when the current tick
would be before the most recently cached tick, due to time going in
reverse.
2020-06-07 22:27:19 +02:00
Swept
a3814dd7c0 Changes PointLightComponent radius from an int to a float. (#1111) 2020-06-07 17:33:03 +02:00
Pieter-Jan Briers
761207fcb4 Update build-test.yml 2020-06-07 17:25:33 +02:00
Pieter-Jan Briers
096c47a1fe Create build-test.yml 2020-06-07 17:18:35 +02:00
ComicIronic
b2cb334f03 Add config var loading from environment variables (#1108) 2020-06-06 23:53:05 +02:00
ComicIronic
caa876dbb3 Fix TickRate causing CurTime jumps (#1106) 2020-06-06 23:50:02 +02:00
Pieter-Jan Briers
c3ee136622 Look at me commiting debug parameters into the code. 2020-06-06 21:59:36 +02:00
Clyybber
6060a2ff4f Improve occlusion performance and fix a crash (#1107) 2020-06-06 19:45:38 +02:00
ComicIronic
dec76c9ad9 Fix lasers changing DrawingHandleWorld transform (#1103) 2020-06-06 14:26:33 +02:00
Pieter-Jan Briers
89ef65b335 Add UI scaling helper APIs and fixes tooltip positions with UI scaling. 2020-06-06 14:13:49 +02:00
Pieter-Jan Briers
12c866b8d6 Fix LayoutContainer margins to be virtual pixels. 2020-06-06 14:13:21 +02:00
Pieter-Jan Briers
537b444eae DebugConsole doesn't spam position changes if hidden. 2020-06-06 14:13:00 +02:00
Pieter-Jan Briers
49b452eca4 Fix layout of buttons at higher UI scaling factors. 2020-06-06 13:02:49 +02:00
Pieter-Jan Briers
2a614e9c3d Squashed commit of the following (PR #1081 + fixes):
commit 46881727ce4107bf61e12cbbdbfa702381debb93
Author: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Date:   Fri Jun 5 23:27:02 2020 +0200

    Fix playing stream storage.

commit 4beef7d66e48c7517ec14f21e0a3ce8db1de57c8
Merge: 6138c00e3 c32f21bea
Author: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Date:   Fri Jun 5 22:45:11 2020 +0200

    Merge branch 'master' into audio

commit 6138c00e3c
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Fri Jun 5 14:23:52 2020 -0500

    refine audiosystem changes

commit 21f9c389e8
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Mon Jun 1 00:50:49 2020 -0500

    remove unused variable

commit ee0cf99edf
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Fri May 29 00:26:41 2020 -0500

    I THINK that fixed the crash. Not sure exactly what though.

commit 4a2e0b3b18
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Fri May 29 00:22:30 2020 -0500

    Remove bloat.

commit 1cddcac705
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Thu May 28 15:35:32 2020 -0500

    fix everything

commit c45dc8fb9d
Author: FL-OZ <anotherscuffed@gmail.com>
Date:   Thu May 28 01:36:45 2020 -0500

    Add server side sound event stopping.
2020-06-05 23:28:14 +02:00
Clyybber
c32f21bea3 Better sound occlusion (#1102)
* Better occlusion; introduce IntersectRayPenetration

* Use ToArray instead of casting

* Better doc

* Use Debug.Assert
2020-06-05 12:53:43 +02:00
Pieter-Jan Briers
dc82748daf Fix some prediction timing anomalies. 2020-06-05 00:14:53 +02:00
Víctor Aguilera Puerto
5c82a4ccb3 Join with MIDI player while stopping it. 2020-06-04 21:03:35 +02:00
Víctor Aguilera Puerto
5473fd183b Ignore invalid MIDI event of type 5 to prevent console spam. 2020-06-04 19:30:46 +02:00
Pieter-Jan Briers
ace88ab20b Revert "Make MsgEntity Reliable like the rest."
This reverts commit d81834c913.

I realized while writing the netcode document that `EntityEvent` is a different message group and am now quite ashamed of myself. This should stay as unreliable, probably.
2020-06-04 19:19:03 +02:00
Clyybber
39c508feaa Fix c#1046 (#1101) 2020-06-03 22:40:04 +02:00
Clyybber
9d6a9d5aa9 Fix #889 (#1100) 2020-06-03 11:52:07 +02:00
Clyybber
3f7296eef4 Fix #1023 (#1099) 2020-06-03 11:49:52 +02:00
ShadowCommander
35c23bd905 Fix UI Control focusing (#1097) 2020-06-02 14:40:16 +02:00
Clyybber
fcdabe98f4 Tiny cleanup (#1098) 2020-06-02 14:40:08 +02:00
Tyler Young
885bcb4f57 Fix up midi stuff, support mild black midis (#1092) 2020-06-02 01:08:56 +02:00
ShadowCommander
1b52093c5d Change buttons to use MouseFilterMode.Stop (#1095) 2020-06-01 15:35:06 +02:00
Pieter-Jan Briers
31c5c9373f GUI tab navigation hotkeys.
Not currently used but I needed these for a quick content hack.
2020-05-31 20:57:47 +02:00
chairbender
d148bde02b Command Binding System supporting multiple bindings (#1089) 2020-05-31 20:44:16 +02:00
Pieter-Jan Briers
29083fdb6f Pass WithFormat<T> through IsValueDefault to fix map saving. 2020-05-31 10:53:30 +02:00
Pieter-Jan Briers
34b39b7db5 Fix performance of YamlConstantSerializer.
It was relying on exceptions for normal control flow, absolutely destroying performance when a debugger is attached.

@ComicIronic please review.
2020-05-31 03:26:31 +02:00
Pieter-Jan Briers
f9df2b141c Disable load context on server ContentStart. 2020-05-31 01:19:00 +02:00
ComicIronic
486fd670e2 Change DrawDepth to int, add content constant hook (#1090)
This allows DrawDepth to be defined in the content layer.
2020-05-31 00:40:48 +02:00
Pieter-Jan Briers
75707c1db0 Use AttachedProperty for TabContainer, TabVisibleProperty. 2020-05-31 00:35:19 +02:00
Pieter-Jan Briers
cb3fe9c138 Adds AttachedProperty<T>.
Generics are useful.
2020-05-31 00:34:56 +02:00
ComicIronic
c9157c8b57 Adds custom YAML serializer for ints in terms of named constants (#1088)
Works similar to the flag serializer, except it allows for magic numbers
to be given names in the YAML.
2020-05-30 12:07:19 +02:00
Víctor Aguilera Puerto
94c868a395 Add missing properties to IMidiRenderer. 2020-05-29 17:19:14 +02:00
Víctor Aguilera Puerto
070ad6989c MIDI improvements
* Handle a few more MIDI events.
* Remove useless MIDI error logging.
* MidiEvent ToString() has useful info.
* Autoload soundfonts from Content.
2020-05-29 17:14:55 +02:00
Pieter-Jan Briers
22615dbf01 Add more useful script globals. 2020-05-28 23:43:34 +02:00
Pieter-Jan Briers
daa817a14a Change log file format to be less awful. 2020-05-28 20:18:49 +02:00
Pieter-Jan Briers
9262cdc555 Stop spamming about late msgentity ok? 2020-05-28 19:56:22 +02:00
Leo
44fcb0232c Adds theyre text macro (#1080) 2020-05-28 17:47:55 +02:00
Pieter-Jan Briers
9eeb1d1afa Fix compiler warnings 2020-05-28 17:44:31 +02:00
Pieter-Jan Briers
6a1249a922 Fix ordering of early entity messages. 2020-05-28 14:32:46 +02:00
20kdc
171a19487b Allow drawing unfilled circles, remove extra (0, 0) point (#1084) 2020-05-28 14:13:45 +02:00
Pieter-Jan Briers
d81834c913 Make MsgEntity Reliable like the rest.
MsgState has been exempt, obviously.
2020-05-28 13:26:47 +02:00
Pieter-Jan Briers
044eeb61f4 Fix OnClose not firing on windows correctly. 2020-05-28 13:18:39 +02:00
Pieter-Jan Briers
263a72ed07 Fix NullRef in PhysicsComponent.RemoveController() 2020-05-28 13:18:25 +02:00
Pieter-Jan Briers
488ce445a0 Shut down physics controllers when PhysicsComponent shuts down. 2020-05-28 00:49:42 +02:00
Pieter-Jan Briers
5b9789870b Fix inheritance overriding behavior on PlacementMode. 2020-05-28 00:27:22 +02:00
Clyybber
9d75c3a1c8 Implement audio occlusion and upgrade to OpenTK 4 (#1068) 2020-05-27 17:50:01 +02:00
Pieter-Jan Briers
782ac26a94 Mark some control properties as animatable. 2020-05-27 14:09:58 +02:00
Pieter-Jan Briers
32c1b1e3b2 Split off SS14 into BaseWindow. 2020-05-27 14:08:52 +02:00
Pieter-Jan Briers
4be2f8c780 Render greek glyphs. 2020-05-26 16:20:47 +02:00
Pieter-Jan Briers
fd204e5a99 Fix rounding error in font atlas code.
This could cause the atlas to be too small at certain configurations.
2020-05-26 16:20:47 +02:00
Pieter-Jan Briers
b8a71db3c8 Adds AnimationCompleted event to Control. 2020-05-26 16:20:47 +02:00
Pieter-Jan Briers
e334d6610e Fix race condition in the Bound UI system.
If you sent multiple state updates on the same frame these could easily arrive in different orders on the client, which is definitely not intended. This fixes that by sending them per frame.

As a result, this also means earlier updates on the same frame are discarded, saving bandwidth.
2020-05-26 16:20:47 +02:00
Pieter-Jan Briers
1e196dfd67 Implement DrawCircle in DrawingHandleScreen 2020-05-26 16:20:47 +02:00
Víctor Aguilera Puerto
8d2dcb23f7 Add InRange to MapCoordinates. 2020-05-26 14:20:22 +02:00
Hugal31
b4eac8526a Implement text macros (#1058) 2020-05-25 20:47:51 +02:00
Jackson Lewis
80536daadf Fix problem with colliding objects getting 'squashed' (#1077) 2020-05-25 20:11:03 +02:00
Jackson Lewis
f03860a16a Fix ICollideBehavior.OnCollide being called multiple times (#1074)
* Fix ICollideBehavior dispatching

* Move collision behavior code to execute after impulse resolution.
2020-05-25 15:41:54 +02:00
zumorica
deebe5b274 Fix crash when MIDI renderer gets deleted 2020-05-25 01:44:39 +02:00
ComicIronic
c26d409aee Add flag serialization markers to collision layer, mask in PhysShapes (#1072) 2020-05-25 01:29:27 +02:00
Jackson Lewis
f675aa95d5 Optimize collision code in physics engine (#1071) 2020-05-25 01:20:08 +02:00
ComicIronic
5ebd8a4221 Add system for using flag names in YAML (#1047) 2020-05-24 22:43:30 +02:00
Pieter-Jan Briers
46b4256d12 Adds MetadataComponent to entityprototype by default to fix map serialization issues.
Otherwise map deserialization fails if a metadata component gets serialized.
2020-05-24 22:11:57 +02:00
Pieter-Jan Briers
79fc210395 Typing into LineEdit when you have a selection replaces the selection. 2020-05-24 17:24:23 +02:00
Pieter-Jan Briers
db5077f96d Adds exception handler to NetMessage callbacks. 2020-05-24 14:48:29 +02:00
Pieter-Jan Briers
fce6662824 Exceptions inside entity deletion do not leave corrupted data. 2020-05-24 14:41:39 +02:00
zumorica
a788cfd998 Fix MIDI crash 2020-05-23 22:03:57 +02:00
Víctor Aguilera Puerto
2dddc03324 Set ResourcePath and SpriteSpecifier inheritors as NetSerializable (#1067) 2020-05-23 12:50:32 +02:00
Pieter-Jan Briers
24eab7ef3a Fix YAML ColorSerializer, optimize Color.ToHex() 2020-05-23 02:38:36 +02:00
Pieter-Jan Briers
fb82568d59 Fix exception in physics system. 2020-05-23 02:38:13 +02:00
Jackson Lewis
274334c926 Rewrite the physics engine (#1037) 2020-05-23 01:21:02 +02:00
Pieter-Jan Briers
2b3bdf0f28 Adds RandomExtensions.Pick for IReadOnlyCollection. 2020-05-23 00:42:37 +02:00
Pieter-Jan Briers
2c5536e982 Adds more script globals.
Also makes them all abstract for code reuse working around a Roslyn bug.
2020-05-22 22:13:11 +02:00
Pieter-Jan Briers
564c39b85a Add more default script imports.
Robust.Shared.Map and Robust.Shared.Prototypes
2020-05-22 22:11:27 +02:00
Pieter-Jan Briers
de82adb6ff Fix exceptions not getting caught on first script submission. 2020-05-22 22:08:51 +02:00
Pieter-Jan Briers
5d3f573f3c Mark AppearanceComponent as dirty on init. 2020-05-22 17:56:49 +02:00
Víctor Aguilera Puerto
149fe47424 Better MIDI (#1062) 2020-05-22 13:07:02 +02:00
Pieter-Jan Briers
cc4069d526 Fix clear button in tile spawn window not resetting search results. 2020-05-21 23:39:14 +02:00
Pieter-Jan Briers
7f508f7719 Show largest clyde batch size in F3. 2020-05-21 13:44:41 +02:00
Clyybber
feb5050b32 Make midi louder (#1063) 2020-05-20 20:24:48 +02:00
chairbender
4e192f9084 Add helper method for statically getting entity systems (#1061) 2020-05-20 16:42:02 +02:00
Pieter-Jan Briers
eb6463fad0 Fix failing test 2020-05-20 16:16:25 +02:00
Pieter-Jan Briers
ffc5c4903c Improve modal closing.
Clicking to close modal now does not handle. Hitting EngineKeyFunctions.CloseModals closes all active modals.
2020-05-20 11:59:19 +02:00
Pieter-Jan Briers
a9d272da62 More KeyBinding improvements:
1. Fixed handling of repeats so that they don't fire stuff incorrectly anymore.
2. Add Priority system to keybinds because apparently C# Sort isn't stable like I thought.
2020-05-20 11:59:19 +02:00
Pieter-Jan Briers
b66658bda5 Re-introduce keybind blocking, move CanFocus around to avoid the initial issue.
CanFocus is now evaluated separately by the input and UI manager so that it is possible to handle handling/UI blocking issues cleaner. This thus makes it possible to re-introduce keybind blocking which is quite useful.
2020-05-20 11:59:19 +02:00
Víctor Aguilera Puerto
424a9c9dfb ServerUserInterfaceComponent can now SetState on a specific player (#1060) 2020-05-18 20:53:03 +02:00
Víctor Aguilera Puerto
4ea42107b5 Increase buffers for MIDI and log MIDI buffer overflows. (#1059) 2020-05-18 15:11:15 +02:00
Swept
b89f8e396d Replaces noSprite.png with Gmod Error Sprite (#1055) 2020-05-18 12:31:24 +02:00
Pieter-Jan Briers
1551ff1ae4 Adds ability to draw arbitrary primitives in Clyde. 2020-05-18 02:29:32 +02:00
Pieter-Jan Briers
4bb3a1e958 Give UITest window a minsize. 2020-05-18 01:47:57 +02:00
Pieter-Jan Briers
2424adbe6e Clean up unused cruft files. 2020-05-17 02:12:00 +02:00
Víctor Aguilera Puerto
e394ade45c Reduce MIDI sample rate (#1057)
* Reduce MIDI sample rate

* Raise buffer count to 11
2020-05-17 01:03:25 +02:00
Pieter-Jan Briers
a72dd8c85b Commits several crimes against humanity in a bad attempt to debug watchdog API issues. 2020-05-14 00:39:08 +02:00
Pieter-Jan Briers
d6b25945e4 Adds AltOrigin functionality property to PopupContainer. 2020-05-13 17:55:33 +02:00
Pieter-Jan Briers
b7f3627ef1 Remove List<>/Dictionary<,> usage from low-level GameState serialization.
NetSerializer does not handle these well and sends the entire backing array instead of a more compact representation. This can then cause it to start sending lists of length 1 with a *capacity* of 4096 resulting in 250 KiB/s down to send updates for a single entity. As it just did on the public server...
2020-05-12 18:34:16 +02:00
Pieter-Jan Briers
6d5c343db3 Modern OpenAL version for Windows. 2020-05-11 11:39:35 +02:00
Pieter-Jan Briers
65abe671aa Allow non-canFocus input commands to actually handle input. 2020-05-08 12:14:20 +02:00
Víctor Aguilera Puerto
40c22563e3 Improves MIDI further (#1048) 2020-05-06 19:21:59 +02:00
Pieter-Jan Briers
f54f4ffe52 Quite possibly break the whole input system.
Made it so keybinds don't block other keybinds from firing.

Why is this necessary? This allows us to have "same keybind, different functionality" binds sanely, like shift click being both TextCursorSelect and (in content) ExamineEntity. Before this change the latter was temporarily broken in UI controls because of TextCursorSelect taking priority and instantly treating the event as handled because it's CanFocus.

The offshoot of this is that all the "args.CanFocus == mouse left" UI code had to be fixed, since multiple things were now firing for that and breaking everything. For example TextCursorSelect actually BROKE because now ExamineEntity was firing inside UI again and that was seen as a left click.

EngineKeyFunctions.UIClick has been introduced as "mouse left for the UI" for this purpose.
2020-05-05 23:58:21 +02:00
Pieter-Jan Briers
57f62dd98a SSE2 accelerate MIDI stereo -> mono for fun and profit. 2020-05-05 15:20:36 +02:00
Víctor Aguilera Puerto
5d4e3ebf9d Midi optimizations. (#1045) 2020-05-05 14:50:04 +02:00
Pieter-Jan Briers
f8e7ded2f0 Handle empty clipboard when pasting text. 2020-05-04 23:38:01 +02:00
Pieter-Jan Briers
51b87513ed Improve LineEdit
Fixes #748, Closes #1010

Can select text now, can move by words, and all the other stuff you'd expect from a control like this.
2020-05-04 17:13:29 +02:00
Pieter-Jan Briers
1f6bd2481f Allow escaping command parsing. 2020-05-03 15:59:15 +02:00
Pieter-Jan Briers
33989aa6e5 Pull texture lookup out of DrawTexture
Small optimization.
2020-05-03 14:38:43 +02:00
Pieter-Jan Briers
3f73aebb52 Fix MapId assignment bug. 2020-05-03 00:03:12 +02:00
Pieter-Jan Briers
3a054641c5 Catch Fluidsynth logging 2020-05-02 22:39:52 +02:00
Pieter-Jan Briers
4020f55f5f Unhardcode culture and provide hook for content to set it. 2020-05-02 19:59:48 +02:00
Pieter-Jan Briers
b63c7eb6ab Fix MIDI audio crackles. 2020-05-02 18:01:55 +02:00
Pieter-Jan Briers
ed6818dafa Report missing map entities only once per type. 2020-05-02 16:05:13 +02:00
metalgearsloth
e78ac25680 AI engine changes (#1042) 2020-05-02 11:19:22 +02:00
ComicIronic
4b50b151fe Minor improvements to printing in VV (#1041) 2020-05-02 00:15:59 +02:00
Pieter-Jan Briers
e5800bdf6b AAAAAAAAH 2020-05-01 20:56:19 +02:00
Pieter-Jan Briers
e21bae3140 Put a note about package_release_build.py in download_natives.py 2020-05-01 20:47:13 +02:00
Pieter-Jan Briers
ee3a1a6cf5 Try to figure out why fluidsynth isn't getting copied 2020-05-01 20:38:42 +02:00
Pieter-Jan Briers
6debbef454 I blame my IDE for this. 2020-05-01 20:06:19 +02:00
Pieter-Jan Briers
ff03de4408 Ship fluidsynth 2020-05-01 19:33:09 +02:00
ComicIronic
8398169183 Change Reference -> Ref in VV (#1040) 2020-05-01 19:04:59 +02:00
Pieter-Jan Briers
aa6af785e5 ScreenshotAsync helper function. 2020-04-30 12:41:53 +02:00
Pieter-Jan Briers
7be309f774 Screenshot API. 2020-04-30 11:56:57 +02:00
Pieter-Jan Briers
a46704507a Remove accidental public modifier. 2020-04-30 01:55:55 +02:00
Pieter-Jan Briers
1776cc5bda Optimize EntityUid.Parse to not allocate for client-side UIDs. 2020-04-30 00:50:19 +02:00
Pieter-Jan Briers
e33bae107b Add .idea/ to .gitignore. 2020-04-30 00:37:20 +02:00
Pieter-Jan Briers
55f51f54a5 Add Robust.Shared.Scripting to solution. 2020-04-30 00:36:46 +02:00
Jackson Lewis
2042312df7 Error is now thrown if entity prototype defines a component twice (#1038) 2020-04-30 00:33:53 +02:00
Pieter-Jan Briers
703c404f11 Fix moving things between maps not updating physics trees correctly. 2020-04-30 00:32:30 +02:00
Pieter-Jan Briers
400dcb06fc Server scripting. 2020-04-30 00:06:59 +02:00
Pieter-Jan Briers
48699837b0 Clear cached PVS relatives set. 2020-04-26 14:47:58 +02:00
Pieter-Jan Briers
b366070cd4 Adds entity prototype editor suffix system. 2020-04-26 01:16:49 +02:00
Pieter-Jan Briers
7c4b1af967 Optimize UserInterfaceSystem and clean up bound user interface API slightly. 2020-04-26 00:51:46 +02:00
Pieter-Jan Briers
9b95065561 PVS/DynamicTree optimizations. 2020-04-26 00:30:15 +02:00
Pieter-Jan Briers
e492e3b521 Parse build.json next to the executable for default build information. 2020-04-25 22:28:32 +02:00
Pieter-Jan Briers
6794bf4c3c Fix phys shapes showing up in map file. 2020-04-25 17:32:41 +02:00
Víctor Aguilera Puerto
bd20511ace Add predicate to Raycast (#1035) 2020-04-24 23:45:19 +02:00
Pieter-Jan Briers
cf87dfde62 Don't include NJsonSchema on release builds.
Saves like 200~ KiB disk space from not having to ship the unused library.
2020-04-24 22:15:57 +02:00
Pieter-Jan Briers
615dcd041b MapLoader reports missing prototypes. 2020-04-24 02:12:12 +02:00
Pieter-Jan Briers
3926de43de Fix GC issues with sound font loader callbacks.
Also slight optimizations.
2020-04-24 02:11:59 +02:00
Jackson Lewis
949b8cd2d9 Fix bug with InteractionOutline on larger sprites (#1034) 2020-04-23 23:52:20 +02:00
Jackson Lewis
db8d9bd228 Gravity (#1031) 2020-04-23 16:49:19 +02:00
Pieter-Jan Briers
797d1acaeb Tweak color gain factor to reduce disparity between walls and non-walls.
Also increases the brightness of *specifically* walls to make up for it, in content.
2020-04-20 18:16:21 +02:00
Pieter-Jan Briers
a380cd9e40 Fix some incorrect naming in TransformComponent 2020-04-20 17:54:33 +02:00
Pieter-Jan Briers
1f64080859 Shamelessly up light cap to 128 as a shoddy bandaid for saltern. 2020-04-20 16:19:58 +02:00
Pieter-Jan Briers
ec5e4e6c8a Cache MapID on TransformComponent. 2020-04-20 16:10:48 +02:00
Pieter-Jan Briers
e2ec1216d9 NoInlining SwapBuffers 2020-04-20 16:10:48 +02:00
Jackson Lewis
10f98e2fca ServerEntityNetworkManager doesn't dispatch messages if the client got disconnected (#1030) 2020-04-20 15:46:11 +02:00
Jackson Lewis
828ada9e22 Split HandleMessage into local and networked variants, add ICommonSession parameter to the latter (#1028) 2020-04-20 09:37:10 +02:00
Pieter-Jan Briers
c770c2dd11 Remove debug logging from ServerEntityManager. 2020-04-19 23:32:40 +02:00
Pieter-Jan Briers
ae756d9ebe Small rendering optimization.
Removes WorldPosition fetch from sprite sort.
2020-04-19 18:27:32 +02:00
Pieter-Jan Briers
76005b0706 Fix assembly loading issues on release builds. 2020-04-19 11:13:03 +02:00
Pieter-Jan Briers
9d293d4dd1 Remove debug logs from prediction. 2020-04-19 01:00:49 +02:00
Pieter-Jan Briers
2f02cb271a Fix tests. 2020-04-19 01:00:39 +02:00
Pieter-Jan Briers
0c8f869cb4 Prediction (#1027) 2020-04-18 17:35:54 +02:00
Pieter-Jan Briers
2da1640ab7 Makes BoxContainer default separation 0. 2020-04-18 12:16:40 +02:00
Pieter-Jan Briers
12fb54904a Fix crash when entity playing sound gets deleted. 2020-04-18 00:33:45 +02:00
Pieter-Jan Briers
fc1bbbf72b Shut down components on deletion in a separate stage.
This means that during shutdown, things like transform are still available. Useful!
2020-04-18 00:13:42 +02:00
Pieter-Jan Briers
5b5be9615a List matching entity UID in lsgrid/lsmap. 2020-04-18 00:13:35 +02:00
Pieter-Jan Briers
964afc523f Fix map entities not being added to their parent's children list. 2020-04-17 23:46:43 +02:00
Pieter-Jan Briers
216433199c Give EntitySystemManager a VV property to get a list of entity systems in VV. 2020-04-17 21:43:33 +02:00
Pieter-Jan Briers
1ab703325f Show type abbreviations for default ToString() implementations. 2020-04-17 21:42:54 +02:00
Pieter-Jan Briers
15386cf506 Fix VV page box having too little width to show anything. 2020-04-17 21:42:28 +02:00
Pieter-Jan Briers
2cc52ea767 Fix sounds playing across dimensions. 2020-04-17 19:01:53 +02:00
Pieter-Jan Briers
48ca01ab4a Fix DeleteGrid messing up the default grids. 2020-04-17 18:45:20 +02:00
Pieter-Jan Briers
832a4e01f1 High level cursor API. 2020-04-17 16:57:51 +02:00
Pieter-Jan Briers
44ce291fed Low level hardware cursor API. 2020-04-17 15:54:09 +02:00
Pieter-Jan Briers
ba933f7db0 Improvements to allow better connection dialog in content. 2020-04-17 14:41:22 +02:00
Pieter-Jan Briers
e353972959 Pass shutdown reason through to net manager so clients get notified correctly. 2020-04-17 12:05:53 +02:00
Pieter-Jan Briers
c3859bd52a New watchdog API system. 2020-04-16 21:20:23 +02:00
Pieter-Jan Briers
f8e0c1fe1d Fix parsing of --cvar command line arguments containing a =. 2020-04-16 21:02:09 +02:00
Pieter-Jan Briers
cd97c6cf43 Entity systems are now still available during shutdown.
Fixes a bug in EyeUpdateSystem shutdown.
2020-04-13 22:25:26 +02:00
Víctor Aguilera Puerto
3d6a3a6216 Add visibility masks to IPlayerSession, add Visibility componen… (#1026) 2020-04-10 16:38:59 +02:00
metalgearsloth
1cdb279319 Add collision change event (#1024)
Used for the pathfinder to keep track of the graph.

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2020-04-09 16:52:16 +02:00
Pieter-Jan Briers
8b90bdf875 Tuple and deconstruct helpers for Vector4 & Color. 2020-04-09 16:46:33 +02:00
Pieter-Jan Briers
6200ba01e6 CMYK helpers on Color. 2020-04-09 16:46:14 +02:00
Pieter-Jan Briers
ab873be4ef Fix awful documentation error. 2020-04-09 02:44:18 +02:00
Injazz
c4ee80a3e8 adds setter to IEntity's Description property (#1020)
Co-authored-by: Injazz <injazza@gmail.com>
2020-04-08 21:24:46 +02:00
PrPleGoo
6d8a0f6558 ISelfSerialize interface (#1021)
* Special check for decimal in serialization code. Changed method in IoCManager for a little QoL

* ISelfSerialize stuff

ISelfSerialize interface for stuff that want to implement their own (de)serialization.
Forgot that desialize could exist for decimals earlier.
Added ViewVariablesPropertyEditorISelfSerialzable thing for viewvariables.

* fix TestStylesheetOverride

* Fix improper UT logic

* Somewhat neater VV lineEdit event hanlding

* remove whitespace and unused using

* uninherit ViewVariablesPropertyEditorISelfSerialzable

* Fix improper use or ToString

* seal VV classes
2020-04-08 21:24:32 +02:00
Pieter-Jan Briers
ec52102d02 Allow controls to override stylesheets for itself and descendants. 2020-04-04 15:07:53 +02:00
Pieter-Jan Briers
9cca7ce8ef Expose client connection state. 2020-04-04 15:07:31 +02:00
Pieter-Jan Briers
7e536954be API for accessing initial launch parameters like --launcher. 2020-04-04 15:06:47 +02:00
Pieter-Jan Briers
e0d8b111bc Remove MainMenu and launcher connecting from engine. 2020-04-04 15:05:10 +02:00
Pieter-Jan Briers
7d6bc63439 Make MidiManager capable of handling absence of Fluidsynth.
So we can enable instruments without crashing platforms without the dll files.
2020-03-30 18:31:12 +02:00
Pieter-Jan Briers
009b41d7f0 Adds ability to specify file dialog filters to IFileDialogManager. 2020-03-30 18:31:12 +02:00
Pieter-Jan Briers
8f96c65312 Fix BoundUserInterface not raising close event if player disconnects. 2020-03-30 18:31:09 +02:00
Víctor Aguilera Puerto
93bb495f4a PlayerManager method to get PlayerSessions that meet a condition (#1019)
* Don't set attached entity name to username.

* You can now get players by a given predicate (think of LINQ's .Where())
2020-03-30 18:29:15 +02:00
PrPleGoo
bb0e6917b8 Decimal reagents requirements (#1018) 2020-03-28 13:48:57 +01:00
Pieter-Jan Briers
09a06c14c5 loginlocal promotes to Host. 2020-03-25 22:30:37 +01:00
Pieter-Jan Briers
1461dc19ae saveconfig command on client. 2020-03-25 22:29:24 +01:00
Pieter-Jan Briers
88d7bc2b6e Don't throw exception on invalid cvar command format. 2020-03-25 22:21:12 +01:00
Pieter-Jan Briers
fd8e68091e Fix implementation, add tests. 2020-03-25 21:34:30 +01:00
Pieter-Jan Briers
e72635155e Merge branch 'master' into expression-based-binding 2020-03-25 18:11:08 +01:00
Pieter-Jan Briers
7dfae37451 no more Prob(80).
Adds assert against that so you don't screw up from BYOND habits.
2020-03-25 18:01:49 +01:00
Pieter-Jan Briers
a21bad1f1b Fix server failing to start.
Damn I'm dumb.
2020-03-25 08:35:45 +01:00
Acruid
a947a38f3c View Rotation (#1016)
* Adds a derived class from Nunit's Is test constraint class.
The game camera can now be rotated.

* Added the new `bind` command to the console, used to bind a key to a keybind.
Added two new keybinds for rotating the View camera left and right.
Added more info to the ""Component does not exist for state" exception.
Added Reduced() and FlipPositive() public functions to Angle.

* Fix a copy/paste bug.

* Adds missing code to bind/unbind CameraRotateLeft.
Camera snapping now actually uses the CameraSnapTolerance constant.
2020-03-25 02:22:18 +01:00
Pieter-Jan Briers
c4b9c1cc4e C# interactive REPL for the client.
It's fancy.
2020-03-25 02:16:00 +01:00
Pieter-Jan Briers
2608229210 [ViewVariables] for ReflectionManager 2020-03-25 02:14:28 +01:00
Pieter-Jan Briers
50abd155c2 Opened() hook for SS14Window 2020-03-25 02:14:01 +01:00
Pieter-Jan Briers
50ad9bacf0 Replace OutputPanel.RemoveLine(int) with RemoveEntry(Index) 2020-03-25 02:13:50 +01:00
Pieter-Jan Briers
d057fdf74f Disable assembly load context on content-start client. 2020-03-25 02:13:23 +01:00
Pieter-Jan Briers
ff1bfde979 Optimize CommandParsing a bit and add tests. 2020-03-25 02:12:23 +01:00
PrPleGoo
2aea10168e Fix issue651 and370 (#1017)
* Switch Mobs and Items DrawDepth

* Add Y compare to SpriteDrawingOrderComparer
2020-03-15 08:05:16 +01:00
ShadowCommander
2f819cf781 Refactor Controls to default to MouseFilterMode.Ignore (#1011)
* Refactor Controls to default to MouseFilterMode.Ignore

* Clean up MouseFilterMode.Ignore from Controls

* Fix BoxContainer eating UI clicks

* Fix ScrollContainer using the wrong variable

* Refactor ContainerButtons to use a StyleClass for formatting instead of typeof

* Refactor BaseButton to work when child has MouseFilter.Pass
2020-03-15 07:29:51 +01:00
PrPleGoo
8cee7ba685 Reworked how friction impacts velocity. (#1015)
* Rework friction to work as a sum instead of indiviually

* Removed comments

* Changed how friction works from reducing movement to increased the effect of mass.
2020-03-15 07:28:32 +01:00
PrPleGoo
5c461a8500 Added unit tests for some collision code and a small rename (#1014)
* Changed how collision checks work

* Undid asym collision

* Push to switch machines

* Added UnitTest to clarify the logic in CollidesOnMask

* moved test into testcase
2020-03-15 07:27:25 +01:00
Acruid
0a32938c23 DebugCoordsPanel now just prints the Map and Grid coordinates. This looks more uniform, gives more info, and saves a line in the pannel. 2020-03-05 14:42:11 -08:00
Tyler Young
3856a16463 flip writing check 2020-02-28 19:12:57 -05:00
Víctor Aguilera Puerto
0a306514a2 IntersectRay can now ignore bodies that aren't hard collidables. (#1008) 2020-02-28 06:35:06 +01:00
ShadowCommander
726341981e Fix StyleBox (#1009) 2020-02-28 06:34:26 +01:00
Pieter-Jan Briers
850d277354 Fix EventBus tests 2020-02-28 06:30:36 +01:00
Tyler Young
38aeca2342 Automatic Partial Shader Reloading (#1005)
* merged in shader automatic reloading, remove internal shader reloading

add support for includes to shader reloading, modified includes reload shaders that depends upon them

* add some fault tolerance to allow playing with the file a bit

* prevent multiple watch attempts

* fix spacing

* revert project change

* add cancellation to Reload with a default of 30s

fix case sensitivity comparison

assume windows & mac are case insensitive
2020-02-28 06:27:35 +01:00
Pieter-Jan Briers
3e62e6d1f6 Fix a bunch of tests 2020-02-28 04:05:56 +01:00
Acruid
d7e0edd1a3 Removed the IEntityManager dependency out of EntityNetManager.
Removed the component message queue inside of EntityManager. There should be no time where messages are coming in before the EntityManager is initialized.
Removed the ability to send EntityEvents, you need to send either component or system messages.
2020-02-27 16:01:19 -08:00
Acruid
8f968760cb Replace IMapManager.FindGridAt with IMapManager.TryFindGridAt.
Grid spatial queries do not return the default grid anymore.
2020-02-27 02:10:18 -08:00
Tyler Young
36ee8a0c90 use generic type to fix call IsValueDefault
found a way to dedupe
2020-02-27 02:37:22 -05:00
Pieter-Jan Briers
d5872ce66d Make transform move messages use EventBus to improve perf. 2020-02-27 01:23:25 +01:00
Pieter-Jan Briers
84b5322e83 Optimize EventBus. 2020-02-27 01:23:03 +01:00
Pieter-Jan Briers
643c76b28e Optimize ComponentManager.GetComponents() 2020-02-27 00:16:08 +01:00
Pieter-Jan Briers
d9ae0efada Fix FOV being broken when lighting is disabled. 2020-02-26 14:03:28 -08:00
Pieter-Jan Briers
d0e537b8b9 Fix GetEntitiesIntersecting for Nullspace. 2020-02-26 14:03:28 -08:00
Swept
2532ecc021 Readme Updates (#998)
* Updates

* Update readme.md

Co-Authored-By: Pieter-Jan Briers <pieterjan.briers@gmail.com>

Co-authored-by: Pieter-Jan Briers <pieterjan.briers@gmail.com>
2020-02-25 22:40:35 -08:00
metalgearsloth
209b94a6f1 Add SnapGrid method to get neighbor GridCoordinates (#1002)
Just saves using a bunch of variables on content-side.
At this stage it's just used for puddles.
2020-02-25 22:38:39 -08:00
Tyler Young
a8f615d64b Fix lockers making items uninteractable (#1004)
* remove setter for MapPosition

change DetachParent to set WorldPosition after re-parenting to correct Map entity or MapGrid entity

* workaround until default grid not needed due to items can't be picked up if map ent parent
2020-02-25 22:31:46 -08:00
Pieter-Jan Briers
3dcdcd7f20 Make it so no broken entity gets created if AllocEntity is called with invalid prototype. 2020-02-25 22:25:42 +01:00
Acruid
fec386b190 Wraps exception handling in ApplyEntityStates with EXCEPTION_TOLERANCE preprocessor directives. This removes the exception handling from debug builds. 2020-02-25 13:07:33 -08:00
Acruid
446e91af28 Wraps game state entity initialization in try/catch blocks so that a single exception will not prevent the entire state from being applied. Broken entities that fail to Initialize/Startup are immediately deleted. 2020-02-25 12:41:30 -08:00
Pieter-Jan Briers
640deaa8e6 "Fix" addmap & loadbp crashing clients when PVS is enabled. 2020-02-25 20:29:05 +01:00
Tyler Young
52358d8fbe minor docs improvement 2020-02-24 20:10:16 -05:00
Tyler Young
b63d02d96d woo 2020-02-24 20:04:17 -05:00
Pieter-Jan Briers
2bb9105ed9 Fix compiler warnings. 2020-02-25 00:50:44 +01:00
Acruid
a2ca399cd0 Refactors SpriteSystem to use the GetEntitiesIntersecting spatial query instead of depth-first traversal of the scene graph, for increased performance. 2020-02-24 13:22:58 -08:00
Acruid
827727e136 Exposes the approximate argument for all spatial query methods in IEntityManager. 2020-02-24 13:20:50 -08:00
Pieter-Jan Briers
0b1f088f8c Better entity exception tolerance (#996)
* Use separate define constants for exception tolerance stuff.

* Improve handling of exceptions during entity creation.

The entity in question now gets marked as deleted immediately.

* Glorious.

* Testing components, tests, wrapper exception type.
2020-02-24 03:56:50 +01:00
Pieter-Jan Briers
fc212f983e Fix PvsEnabled not being respected correctly. 2020-02-24 03:05:35 +01:00
Pieter-Jan Briers
32bafb66a8 Shadows & FOV. (#992)
* Work on shadow casting.

* Shadowcasting depth works, code cleanup

* Adds #include support to SWSL parser.

* Move lighting shader to swsl.

Also more shader parser fixes.

* Move PI constant to correct file.

* Got functional FOV, working on wall bleed.

* Hey, it kinda works.

* Occluder component now lives in shared.

* Optimizations.

* Fix light map color format.

I set it to something else while testing perf.

* Front face cull final FOV pass.

* Fix holes in occlusion geometry due to disabled occluders.

* Starting work on better wall handling.

* Some comments.

* Improve font-face-culled FOV pass.

* Improve various light biasing things.

* VSM, smooth shadows.

Also unused VSM blurring because it didn't work but committing it like this will forever keep it in Git somewhere.

* FOV smoothing, looks kinda awful.

* Base wall bleed blur strength on camera size.

* The part where I give up.

* Comments. Many comments.

* Allow eyes to disable FOV.

* Improve OccluderComponent on the client.

* Update for occluder component changes.

* Maybe do this properly...
2020-02-23 17:18:58 +01:00
Pieter-Jan Briers
5f4cd8f98a Fix crash on map deletion. 2020-02-23 17:05:53 +01:00
Pieter-Jan Briers
4fa7fa89ef Fix stack overflow in PVS. 2020-02-23 15:50:16 +01:00
Tyler Young
214f9f0323 Implement client bubble PVS. (#983)
* bubble implementation

include contained entities

fix line edit crash when clipboard contents are null somehow

use CVar for update bubble range

remove seenMovers that get NaN'd out of MaxUpdateRange - huge reduction in network traffic from bullets

cut default of MaxUpdateRange down to 12.5 for now

maybe handle teleported things

handle removing player state on disconnect

fixed positional audio errors

make UpdateEntityTree also update player's last seen ents

make net.maxupdaterange cvar tunable at runtime w/o impacting performance

back to position nan as means to hide from client

revert work pooling as the wrong player was getting the wrong game state

ffs needed to think less about *if* something is *seen* and more about *when* it must be *unseen*

clean up usings

handle parenting and sequencing issues that arise on the client

gather needed ents to update recursively

applied suggestions from code review

fix missing recursively contained ents

make assumption that client last saw things on first tick instead of tick zero, as zero would be the "from tick" and first would be he "to tick"

add First tick as constant to GameTick due to relevance above

renamed includedEnts to checkedEnts to make usage more clear

added comments

inverted some conditions to flatten parts of the pvs logic

fixed sending states when already seen (lastChange < lastSeen to lastChange <= lastSeen)

fix sending states when no actual changes (other bugs?)

local caching of currentTick, remove priorTick

* make TransformComponent's Parent setter call Dirty() to handle replicating network state if AttachParent isn't invoked

* fixed parent changed by setting Parent on Transform not updating parent's Children collection and other stuff

rotating parent entities now are visible with their orbiting children if one of their children moves into view

* break out duplicated code as GetLastSeen

* remove unused net.parallelstates

introduce net.pvs to configure enabling/disabling PVS
2020-02-23 14:42:54 +01:00
Acruid
2cacf00d1a The VV system now has a PropertyEditor for EntityUid.
The Parent EntityUid property is now exposed on ITransformComponent.
2020-02-22 14:36:45 -08:00
Acruid
a5e47d9307 Adds more unit tests for EntityEventBus. 2020-02-22 12:49:17 -08:00
Acruid
728f58465d EntitySystem Event Refactor (#989)
* Removed the EntitySystem event implementation, it now uses the more advanced EventBus.
Removed EntitySystem.RegisterMessageTypes() function.
Removed EntitySystem.SubscribeEvents() function.
Added EntitySystemMessage.NetChannel field. This holds the remote net channel the event originated from.

* Removed the Sender object from events. If you needed this field, add it to the event class.

* Removed unused event proxy methods from Entity.
SubscribeEvent() has been split into SubscribeNetworkEvent() and SubscribeLocalEvent() methods on EntitySystem.
Most methods on EntityEventBus now require callers to specify the source (Local or Network) of the events.
2020-02-22 17:59:43 +01:00
ShadowCommander
91467ecdb9 Implement HistoryLineEdit (#990)
* Implement HistoryLineEdit

* Refactor DebugConsole to use HistoryLineEdit

* Clean up LineEdit

Add args.Handle() for each BoundKeyFunction

Clean up if statements

* Rearrange LineEdit variables

* Reimplement DebugConsole saving and loading
2020-02-22 17:56:35 +01:00
ShadowCommander
2a825ffe9e Fix ButtonGroup (#991) 2020-02-21 12:19:17 +01:00
Pieter-Jan Briers
e7d5604889 Fix assemblies not being loaded into correct load context in certain circumstances. 2020-02-21 12:18:53 +01:00
Pieter-Jan Briers
eae2a9283d Fix compiler warnings 2020-02-17 13:57:18 +01:00
Pieter-Jan Briers
b282881482 Key name API, slight input manager cleanup. (#985)
* Adds API for retrieving correct key names & key combination strings.

* Remove (most) bit flag stuff from InputManager.cs.

Replaced it with a union.
2020-02-17 11:13:12 +01:00
ShadowCommander
3b49e0df82 Implement ContainerButton and refactor buttons (#975)
* Add style to TextureRect

* Implement ContainerButton

ContainerButton is a button that resizes to fit the Controls it contains.

* Refactor OptionButton to use ContainerButton

This allows OptionButton to have an inverted triangle icon on the right to make it more obvious that the button is an OptionButton.

* Fix Popup not updating size when opened

* Fix DrawMode not getting updated when _pressed is changed

* Refactor Button to inherit from ContainerButton

* Refactor CheckBox to inherit from ContainerButton

* Fix Control.StyleClasses.GetEnumerator

It was calling GetEnumerator in an infinite loop instead of getting _styleClasses.GetEnumerator like it was supposed to do.

* Update Button references

* Fix Styling
2020-02-17 11:06:16 +01:00
Pieter-Jan Briers
cb095b28bd Fix not being able to VV content components on release. 2020-02-15 21:56:37 +01:00
Pieter-Jan Briers
a07c068a8c Implement lsasm command.
Just something I needed to debug something.
2020-02-15 21:53:56 +01:00
Pieter-Jan Briers
44c7ff552e Optimizations.
Removed use of ConcurrentDictionary. It was slow.
Other minor optimizations around the codebase.
Added option for parallel game state generation. Seems slower than doing it single-threaded so off by default for now.
2020-02-15 17:22:32 +01:00
Pieter-Jan Briers
115795c38e Game state netcode improvements (#978)
* Fix server sending ALL game states reliably.

Now only large enough game states get sent reliably. This means that when a single client stops ACKing the server isn't spamming a bunch of massive game states into Lidgren to reliably deliver.

* Do not send prototype-duplicated data in game  states.

This cuts out component states and ComponentChanged data if this can already be inferred by deserialization of the prototype on the client.

* More comments.

* Remove debugging code.

* Use GetNetComponents instead of GetAllComponents.

Nice little optimization.
2020-02-15 13:45:52 +01:00
moneyl
e2ce1ffb2a Improve error handling and help messages on several console comm… (#980)
For `loglevel`, `testlog`, and `gc`.
2020-02-15 13:41:41 +01:00
Pieter-Jan Briers
69c2163988 Fix input commands firing even if GUI handles them. 2020-02-15 01:41:10 +01:00
Pieter-Jan Briers
a0c1415873 Update Lidgren to master from the repo. (#979)
Should improve stability or whatever. Also some convenient stream features.
2020-02-15 01:21:30 +01:00
4dplanner
4470443445 SpriteView checks for deleted sprites (#977) 2020-02-13 23:12:05 +01:00
ShadowCommander
b9fdda85ef Add check to LineEdit cursor position (#971) 2020-02-13 13:35:02 +01:00
Tyler Young
a3a8a8b3cf Use Kestler for StatusHost (#966)
* implement StatusHost as a minimal Kestler based HTTP Rest service

break up and organize StatusHost

* handle weird disposal mechanics exposed by testing facility
2020-02-09 23:16:16 +01:00
Acruid
f5c4012408 Fixes issues with certain components that prevented network interpolation from working.
Added try/catch around call to IComponent.HandleComponentState().
Prevent interpolating entities with large changes in position (teleporting).
2020-02-09 02:24:07 -08:00
ShadowCommander
56bda966ba Fix client reconnect after getting disconnected (#965)
The _clientConnectionState wasn't reset to NotConnecting when disconnected by the server (compared to the client disconnecting from the server).
2020-02-09 10:26:24 +01:00
Tyler Young
8bcc5808cc Console commands; gc_mode and szr_stats (#964)
* add some console commands; gc_mode and szr_stats

* add latency mode list to gc_mode
2020-02-09 10:15:01 +01:00
Pieter-Jan Briers
76956448e6 Set max connections count in Lidgren. 2020-02-08 23:13:44 +01:00
Pieter-Jan Briers
179267df24 Add [ViewVariables] to LocalPlayer. 2020-02-08 21:51:43 +01:00
Pieter-Jan Briers
2322aa6aa8 Allow modifying send and receive buffer sizes on the NetPeerConfiguration. 2020-02-08 21:22:36 +01:00
Pieter-Jan Briers
4a1dd9a650 Add CanAdminPlace permission and adds ability for content to block placement. 2020-02-08 20:41:17 +01:00
Tyler Young
42c22c1041 Physics fixes (#963)
DynamicTree now no longer uses a ConcurrentDictionary for proxy look ups
2020-02-08 20:07:13 +01:00
Pieter-Jan Briers
64a8708762 Fix crashes from deleting oneself. 2020-02-08 17:10:37 +01:00
Pieter-Jan Briers
bc630d9b01 Disable status host in integration tests. 2020-02-08 15:36:48 +01:00
Pieter-Jan Briers
ecd4bbbba3 Change default for status to bind to *. 2020-02-08 15:30:18 +01:00
Tyler Young
b6e0359b06 Correct ray casting (#957)
fix weird merge artifacts

fix aabb extraction happening too early on ray casting
2020-02-08 11:05:18 +01:00
moneyl
a8618b339e Fix crash when playing audio on grid that does not exist (#959)
Adds a check to the `PlayAudioPositionalMessage` case of client `AudioSystem` to make sure the grid it's playing on actually exists. If it doesn't, an error is logged and the message is ignored instead of crashing the client.
2020-02-08 11:03:58 +01:00
Pieter-Jan Briers
7841368eeb Allow server to specify custom content pack downloads. 2020-02-08 11:03:20 +01:00
Tyler Young
5d37780f4e Have PhysicsManager use DynamicTree (#955)
* have PhysicsManager use DynamicTree

* remove BroadPhaseNative

add BroadPhase wrapping DynamicTree

replace IBroadPhase with regards to DynamicTree

* add collision enumeration capability for proper BroadPhase

* fix slow app exit due to MapId being unavailable at various stages of shutdown

reduce code footprint of alternate query in AnyEntitiesIntersecting by using existing query (only used rarely)
2020-02-07 15:15:33 -08:00
Pieter-Jan Briers
b3288d1d5c Work around OpenGL drivers not respecting GL_DEBUG_OUTPUT_SYNCHRONOUS. 2020-02-08 00:13:17 +01:00
Tyler Young
3cc10f7eb7 Fix crash from destruction of containers containing containers (#956) 2020-02-07 17:53:22 +01:00
Víctor Aguilera Puerto
8a2ae5ec85 Makes spawnlist use prototype ID if prototype name is null or em… (#954) 2020-02-06 16:12:34 +01:00
Pieter-Jan Briers
568dee4c55 SpriteSystem optimizations. 2020-02-06 16:10:14 +01:00
Pieter-Jan Briers
3d30e86e8c Fix CullDeletedEntities() not working. 2020-02-06 16:09:51 +01:00
Pieter-Jan Briers
418e40d254 Optimize EntityManager.GetEntitiesIntersecting
Removes a stray .ToArray().
2020-02-06 14:39:03 +01:00
Pieter-Jan Briers
0df2d7c89d More Clyde refactoring, FOV works now. 2020-02-06 14:14:27 +01:00
Tyler Young
755675eaab Introduce DynamicTree, Separate Ray from CollisionRay (#951)
* separates Rays from CollisionRays, removing collision masking from Ray

* Entity, ClientEntityManager and EntityManager classes occasionally need to UpdateEntityTree

Entity intersection queries now use a DynamicTree

DynamicTree now correctly reports Count and separately NodeCount

DynamicTree now has optionally precise queries

DynamicTree no longer incorrectly Adds on AddOrUpdate if Update is not necessary

Entity startup now starts Transform, then Collidable, then remaining components

EntityManger's Entity dictionary is now a ConcurrentDictionary to support iteration under modification

DynamicTree freeing root leaf no longer results in invalid tree

SnapGridComponent has been extended to support additional area and directional queries

* added lots of calls to UpdateEntityTree, will need to scale back during review

fixed moved/changed AABB updates to DynamicTree, missed a ref

converted other methods in EntityManager to use the tree for spatial queries

* add unit tests for DynamicTree

make Capacity and EnsureCapacity public, setting Capacity will call EnsureCapacity

* fix brace style

* Box2 Grow -> Enlarged, Combine -> Union
2020-02-06 14:13:15 +01:00
Acruid
58b460e9f5 Removes incorrect debug assertion, resolves https://github.com/space-wizards/RobustToolbox/issues/953. 2020-02-05 12:15:39 -08:00
Acruid
1545340d5c Fixed bug in matrix multiplication that caused entities to be drawn in the wrong spot in the world. 2020-02-04 22:24:22 -08:00
Pieter-Jan Briers
0169312c0b Not actually functional FOV system.
There's enough various changes in here that this is worth committing already.
2020-02-05 00:10:58 +01:00
Quantomicus
cff6a9a5a7 Remove selector support in the RSI format (#952) 2020-02-04 23:43:27 +01:00
Quantomicus
3d34265c6f Fixes #923 (#950) 2020-02-04 19:14:44 +01:00
Tad Hardesty
f8037df56a Replace TransformComponent.OnMove with component message (#946) 2020-02-03 18:05:55 +01:00
moneyl
21cd0f41b4 Increase default vv window size for convenience (#948)
Makes all tabs and information visible by default instead of needing to resize every vv window.
2020-02-03 18:05:30 +01:00
Tad Hardesty
41fa37b955 Update Travis to Bionic and Python 3.6 (#947)
* Update Travis to Python 3.6

* Let's try bionic

* It's just python3 on bionic

* apt update

* Maybe this

* Use generic build image

* >defaults to Ruby
2020-02-03 18:03:40 +01:00
Pieter-Jan Briers
76933003ad Improve native downloading spaghetti, use own Freetype on macOS 2020-01-30 13:29:19 +01:00
Pieter-Jan Briers
322ac488a1 Split part of Clyde rendering off to another file. 2020-01-28 17:05:47 +01:00
1329 changed files with 82776 additions and 41184 deletions

View File

@@ -19,7 +19,7 @@ install:
before_build:
- cmd: py -3.5 -m pip install --user requests
- cmd: py -3.5 RUN_THIS.py --no-prompt
- cmd: git submodule update --init --recursive
- ps: >
if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER -And $env:APPVEYOR_REPO_BRANCH -Eq "master")
{

View File

@@ -1,13 +1,13 @@
root = true
root = true
[*]
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
charset = utf-8-bom
charset = utf-8
[*.{csproj,xml,yml,dll.config,targets}]
[*.{csproj,xml,yml,dll.config,targets,props}]
indent_size = 2
[*.gdsl]

17
.github/CODEOWNERS vendored
View File

@@ -1,14 +1,7 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# Last match in file takes precedence.
# These owners will be the default owners for everything in the repo.
# * @defunkt
* @Acruid @PJB3005 @Silvertorch5
# Be they Fluent translations or Freemarker templates, I know them both!
*.ftl @RemieRichards
# Order is important. The last matching pattern has the most precedence.
# So if a pull request only touches javascript files, only these owners
# will be requested to review.
# *.js @octocat @github/js
# You can also use email addresses if you prefer.
# docs/* docs@example.com
# Ping for all PRs
* @Acruid @PJB3005 @Silvertorch5

31
.github/workflows/build-test.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Build & Test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
- name: Test Engine
run: dotnet test --no-build Robust.UnitTesting/Robust.UnitTesting.csproj -v n

77
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
#on:
# push:
# branches: [ master ]
# pull_request:
# # The branches below must be a subset of the branches above
# branches: [ master ]
# schedule:
# - cron: '30 18 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'csharp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
- name: Build
run: dotnet build
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

53
.github/workflows/publish-client.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Publish Client Build
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Parse version
id: parse_version
shell: pwsh
run: |
$ver = [regex]::Match($env:GITHUB_REF, "refs/tags/v?(.+)").Groups[1].Value
echo ("::set-output name=version::{0}" -f $ver)
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
- name: Package client
run: Tools/package_client_build.py -p windows mac linux
- name: Shuffle files around
run: |
mkdir "release/${{ steps.parse_version.outputs.version }}"
mv release/*.zip "release/${{ steps.parse_version.outputs.version }}"
- name: Upload files to centcomm
uses: appleboy/scp-action@master
with:
host: centcomm.spacestation14.io
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
source: "release/${{ steps.parse_version.outputs.version }}"
target: "/var/lib/robust-builds/builds/"
strip_components: 1
- name: Update manifest JSON
uses: appleboy/ssh-action@master
with:
host: centcomm.spacestation14.io
username: robust-build-push
key: ${{ secrets.CENTCOMM_ROBUST_BUILDS_PUSH_KEY }}
script: /home/robust-build-push/push.ps1 ${{ steps.parse_version.outputs.version }}

41
.github/workflows/test-content.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Test content master against engine
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out content
uses: actions/checkout@v2
with:
repository: space-wizards/space-station-14
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100
- name: Disable submodule autoupdate
run: touch BuildChecker/DISABLE_SUBMODULE_AUTOUPDATE
- name: Check out engine version
run: |
cd RobustToolbox
git fetch origin ${{ github.sha }}
git checkout FETCH_HEAD
git submodule update --init --recursive
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Content.Tests
run: dotnet test --no-build Content.Tests/Content.Tests.csproj -v n
- name: Content.IntegrationTests
run: dotnet test --no-build Content.IntegrationTests/Content.IntegrationTests.csproj -v n

5
.gitignore vendored
View File

@@ -93,3 +93,8 @@ __pycache__
.mypy_cache
MSBuild/Robust.Custom.targets
.idea/
release/

15
.gitmodules vendored Normal file
View File

@@ -0,0 +1,15 @@
[submodule "NetSerializer"]
path = NetSerializer
url = https://github.com/space-wizards/netserializer
[submodule "Lidgren.Network"]
path = Lidgren.Network/Lidgren.Network
url = https://github.com/space-wizards/lidgren-network-gen3.git
[submodule "XamlX"]
path = XamlX
url = https://github.com/space-wizards/XamlX
[submodule "Robust.LoaderApi"]
path = Robust.LoaderApi
url = https://github.com/space-wizards/Robust.LoaderApi.git
[submodule "ManagedHttpListener"]
path = ManagedHttpListener
url = https://github.com/space-wizards/ManagedHttpListener.git

View File

@@ -1,43 +0,0 @@
language: csharp
dist: trusty
sudo: false
mono: none
# dotnet: 3.1.100 # Travis is shitting itself right now and it can't locate .NET Core packages.
os:
- linux
#- osx
addons:
apt:
#sources:
#- deadsnakes
packages:
- python3.5
- python3-pip
cache:
directories:
- packages/
- Dependencies/
- Robust.Client.Godot/.mono/assemblies/
install:
- curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --version 3.1.100
#before_install:
# - if [ $TRAVIS_OS_NAME = osx ]; then brew update && brew upgrade python; fi
before_script:
#- "pyenv versions"
#- "if [ $TRAVIS_OS_NAME = linux ]; then pyenv shell 3.6; fi"
#- "python3.6 -m pip --v"
#- "python3.6 -m pip install --user --upgrade requests"
- "python3.5 -m pip install --user requests"
- "python3.5 RUN_THIS.py --no-prompt"
script:
- "Tools/run_travis.sh"

View File

@@ -1 +0,0 @@
INSTALLED_HOOKS_VERSION

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is a dummy .csproj file to check things like submodules.
Better this than other errors.
If you want to create this kind of file yourself, you have to create an empty .NET application,
Then strip it of everything until you have the <Project> tags.
VS refuses to load the project if you make a bare project file and use Add -> Existing Project... for some reason.
You want to handle the Build, Clean and Rebuild tasks to prevent missing task errors on build.
If you want to learn more about these kinds of things, check out Microsoft's official documentation about MSBuild:
https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild
-->
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Choose>
<When Condition="'$(Python)' == ''">
<PropertyGroup>
<Python>python3</Python>
<Python Condition="'$(OS)'=='Windows_NT' Or '$(OS)'=='Windows'">py -3</Python>
</PropertyGroup>
</When>
</Choose>
<PropertyGroup>
<ProjectGuid>{D0DA124B-5580-4345-A02B-9F051F78915F}</ProjectGuid>
<OutputType>Library</OutputType>
<TargetFrameworkMoniker>.NETFramework, Version=v4.6.1</TargetFrameworkMoniker>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' " />
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' " />
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<Target Name="Build">
<Exec Command="$(Python) git_helper.py" CustomErrorRegularExpression="^Error" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Build" />
<Target Name="Clean">
<Message Importance="low" Text="Ignoring 'Clean' target." />
</Target>
<Target Name="Compile" />
<Target Name="CoreCompile" />
</Project>

View File

@@ -1,105 +0,0 @@
#!/usr/bin/env python3
# Installs git hooks, updates them, updates submodules, that kind of thing.
import subprocess
import sys
import os
import shutil
from pathlib import Path
from typing import List
BUILD_CHECKER_PATH = Path(Path(__file__).resolve().parent)
SS14_ROOT_PATH = Path(BUILD_CHECKER_PATH.parent)
SOLUTION_PATH = Path(SS14_ROOT_PATH/"SpaceStation14.sln")
CURRENT_HOOKS_VERSION = "2" # If this doesn't match the saved version we overwrite them all.
QUIET = "--quiet" in sys.argv
NO_HOOKS = "--nohooks" in sys.argv
def run_command(command: List[str], capture: bool = False) -> subprocess.CompletedProcess:
"""
Runs a command with pretty output.
"""
text = ' '.join(command)
if not QUIET:
print("$ {}".format(text))
sys.stdout.flush()
completed = None
if capture:
completed = subprocess.run(command, cwd=str(SS14_ROOT_PATH), stdout=subprocess.PIPE)
else:
completed = subprocess.run(command, cwd=str(SS14_ROOT_PATH))
if completed.returncode != 0:
raise RuntimeError("Error: command exited with code {}!".format(completed.returncode))
return completed
def update_submodules():
"""
Updates all submodules.
"""
status = run_command(["git", "submodule", "update", "--init", "--recursive"], capture=True)
if status.stdout.decode().strip():
print("Git submodules changed. Reloading solution.")
reset_solution()
def install_hooks():
"""
Installs the necessary git hooks into .git/hooks.
"""
# Read version file.
hooks_version_file = BUILD_CHECKER_PATH/"INSTALLED_HOOKS_VERSION"
if os.path.isfile(str(hooks_version_file)):
with open(str(hooks_version_file), "r") as f:
if f.read() == CURRENT_HOOKS_VERSION:
if not QUIET:
print("No hooks change detected.")
return
with open(str(hooks_version_file), "w") as f:
f.write(CURRENT_HOOKS_VERSION)
print("Hooks need updating.")
hooks_target_dir = SS14_ROOT_PATH/".git"/"hooks"
hooks_source_dir = BUILD_CHECKER_PATH/"hooks"
if not os.path.exists(str(hooks_target_dir)):
os.makedirs(str(hooks_target_dir))
# Clear entire tree since we need to kill deleted files too.
for filename in os.listdir(str(hooks_target_dir)):
os.remove(str(hooks_target_dir/filename))
for filename in os.listdir(str(hooks_source_dir)):
print("Copying hook {}".format(filename))
shutil.copy2(str(hooks_source_dir/filename), str(hooks_target_dir/filename))
def reset_solution():
"""
Force VS to think the solution has been changed to prompt the user to reload it,
thus fixing any load errors.
"""
with SOLUTION_PATH.open("r") as f:
content = f.read()
with SOLUTION_PATH.open("w") as f:
f.write(content)
def main():
if not NO_HOOKS:
install_hooks()
update_submodules()
if __name__ == '__main__':
main()

View File

@@ -1,19 +0,0 @@
#!/bin/bash
gitroot=`git rev-parse --show-toplevel`
cd "$gitroot/BuildChecker"
if [ -f "git_helper.py" ]
then
if [[ `uname` == MINGW* || `uname` == CYGWIN* ]]; then
# Windows
# Can't update hooks from here because we are a hook,
# and the file is read only while it's used.
# Thanks Windows.
py -3 git_helper.py --quiet --nohooks
else
# Not Windows, so probably some other Unix thing.
python3 git_helper.py --quiet
fi
fi

View File

@@ -1,5 +0,0 @@
#!/bin/bash
# Just call post-checkout since it does the same thing.
gitroot=`git rev-parse --show-toplevel`
bash "$gitroot/.git/hooks/post-checkout"

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>SS14</string>
<key>CFBundleDisplayName</key>
<string>Space Station 14</string>
<key>CFBundleExecutable</key>
<string>SS14</string>
<!--
Just a note about this icon.
MacOS seems REALLY iffy about this and even when the file is correct,
it can take forever before it decides to actually update it and display it.
TL;DR Apple is stupid.
-->
<key>CFBundleIconFile</key>
<string>ss14</string>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
#!/bin/sh
# cd to file containing script or something?
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
cd "$BASEDIR"
exec ../Resources/Robust.Client "$@"

View File

@@ -1,4 +0,0 @@
root = false
[*.cs]
indent_style = tab

View File

@@ -1,10 +0,0 @@
* The NetBuffer object is gone; instead there are NetOutgoingMessage and NetIncomingMessage objects
* No need to allocate a read buffer before calling ReadMessage

View File

@@ -1,113 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.page
{
width: 700px;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Peer/server discovery</title>
</head>
<body>
<table>
<tr>
<td class="page">
<h1>Peer/server discovery</h1>
<p>
Peer discovery is the process of clients detecting what servers are available. Discovery requests can be made in two ways;
locally as a broadcast, which will send a signal to all peers on your subnet. Secondly you can contact an ip address directly
and query it if a server is running.
</p>
<p>Responding to discovery requests are done in the same way regardless of how the request is made.</p>
<p>Here's how to do on the client side; ie. the side which makes a request:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Enable DiscoveryResponse messages</span></pre>
<pre class="cl">config.EnableMessageType(<span class="cb2">NetIncomingMessageType</span>.DiscoveryResponse);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb1">// Emit a discovery signal</span></pre>
<pre class="cl">Client.DiscoverLocalPeers(14242);</pre>
</div>
<p>This will send a discovery signal to your subnet; Here's how to receive the signal on the server side, and send a response back to the client:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Enable DiscoveryRequest messages</span></pre>
<pre class="cl">config.EnableMessageType(<span class="cb2">NetIncomingMessageType</span>.DiscoveryRequest);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb1">// Standard message reading loop</span></pre>
<pre class="cl"><span class="cb3">while</span> ((inc = Server.ReadMessage()) != <span class="cb1">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (inc.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DiscoveryRequest:</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb1">// Create a response and write some example data to it</span></pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">NetOutgoingMessage</span> response = Server.CreateMessage();</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; response.Write(<span class="cb4">&quot;My server name&quot;</span>);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb1">// Send the response to the sender of the request</span></pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Server.SendDiscoveryResponse(response, inc.SenderEndpoint);</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
</div>
<p>When the response then reaches the client, you can read the data you wrote on the server:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Standard message reading loop</span></pre>
<pre class="cl"><span class="cb3">while</span> ((inc = Client.ReadMessage()) != <span class="cb1">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (inc.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DiscoveryResponse:</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(<span class="cb4">&quot;Found server at &quot;</span> + inc.SenderEndpoint + <span class="cb4">&quot; name: &quot;</span> + inc.ReadString());</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,22 +0,0 @@
Improvements over last version of library:
* New delivery type: Reliable sequenced (Lost packets are resent but late arrivals are dropped)
* Disconnects and shutdown requests are now queued properly, so calling shutdown will still send any queued messages before shutting down
* All messages are pooled/recycled for zero garbage
* Reduced CPU usage and lower latencies (in the <1 ms range, but still) due to better socket polling
* All public members of NetPeer/NetConnection are completely thread safe
* Larger number of delivery channels
* More exact roundtrip measurement
* Method serialize entire objects via reflection
* Unique identifier now exists for all peers/connections
* More flexible peer discovery; filters possible and arbitrary data can be sent with response
* Much better protection against malformed messages crashing the app
API enhancements:
* NetPeerConfiguration immutable properties now locked once NetPeer is initialized
* Messages cannot be send twice by accident
* Impossible to confuse sending and receiving buffers since they're different classes
* No more confusion if user should create a buffer or preallocate and reuse

View File

@@ -1,17 +0,0 @@
PER MESSAGE:
7 bits - NetMessageType
1 bit - Is a message fragment?
[8 bits NetMessageLibraryType, if NetMessageType == Library]
[16 bits sequence number, if NetMessageType >= UserSequenced]
8/16 bits - Payload length in bits (variable size ushort)
[16 bits fragments group id, if fragmented]
[16 bits fragments total count, if fragmented]
[16 bits fragment number, if fragmented]
[x - Payload] if length > 0

View File

@@ -1,115 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Lidgren tutorial</title>
</head>
<body>
<table>
<tr>
<td width="700">
<h1>Simulating bad network conditions</h1>
<p>
On the internet, your packets are likely to run in to all kinds of trouble. They will be delayed and lost and they might even arrive multiple times at the destination. Lidgren has a few option to simulate how your application or game will react when this happens.<br />
They are all configured using the NetPeerConfiguration class - these properties exists:</p>
<p>
<div class="cf">
<table>
<tr>
<td valign="top">
<b>SimulatedLoss</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is a float which simulates lost packets. A value of 0 will disable this feature, a value of 0.5f will make half of your sent packets disappear, chosen randomly. Note that packets may contain several messages - this is the amount of packets lost.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>SimulatedDuplicatesChance</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is a float which determines the chance that a packet will be duplicated at the destination. 0 means no packets will be duplicated, 0.5f means that on average, every other packet will be duplicated.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>SimulatedMinimumLatency</b><br />
<b>SimulatedRandomLatency</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
These two properties control simulating delay of packets in seconds (not milliseconds, use 0.05 for 50 ms of lag). They work on top of the actual network delay and the total delay will be:<br />
Actual one way latency + SimulatedMinimumLatency + [Randomly per packet 0 to SimulatedRandomLatency seconds]
</td>
</tr>
</table>
</div>
<p>It's recommended to assume symmetric condtions and configure server and client with the same simulation settings.</p>
<p>Simulating bad network conditions only works in DEBUG builds.</p>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,17 +0,0 @@
Completed features:
* Message coalescing
* Peer, connection statistics
* Lag, loss and duplication simulation for testing
* Connection approval
* Throttling
* Clock synchronization to detect jitter per packet (NetTime.RemoteNow)
* Peer discovery
* Message fragmentation
Missing features:
* Receipts 25% done, need design
* More realistic lag/loss (lumpy)
* Detect estimated packet loss
* More advanced ack packet

View File

@@ -1,206 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Lidgren basics tutorial</title>
</head>
<body>
<table>
<tr>
<td width="700">
<h1>
Lidgren basics</h1>
<p>
Lidgren network library is all about messages. There are two types of messages:</p>
<li>Library messages telling you things like a peer has connected or diagnostics messages (warnings, errors) when unexpected things happen.</li>
<li>Data messages which is data sent from a remote (connected or unconnected) peer.</li>
<p>
The base class for establishing connections, receiving and sending message are the NetPeer class. Using it you can make a peer-to-peer network, but if you are creating a server/client topology there are special classes called NetServer and NetClient. They inherit NetPeer but sets some defaults and includes some helper methods/properties.</p>
<p>
Here's how to set up a NetServer:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetPeerConfiguration</span> config = <span class="cb3">new</span> <span class="cb2">NetPeerConfiguration</span>(<span class="cb4">&quot;MyExampleName&quot;</span>);</pre>
<pre class="cl">config.Port = 14242;</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb2">NetServer</span> server = <span class="cb3">new</span> <span class="cb2">NetServer</span>(config);</pre>
<pre class="cl">server.Start();</pre>
</div>
<p>
The code above first creates a configuration. It has lots of properties you can change, but the default values should be pretty good for most applications. The string you provide in the constructor (MyExampleName) is an identifier to distinquish it from other applications using the lidgren library. Just make sure you use the same string in both server and client - or you will be unable to communicate between them.</p>
<p>
Secondly we've set the local port the server should listen to. This is the port number we tell the client(s) what port number to connect to. The local port can be set for a client too, but it's not needed and not recommended.</p>
<p>
Thirdly we create our server object and fourth we Start() it. Starting the server will create a new network thread and bind to a socket and start listening for connections.</p>
<p>
Early on we spoke about messages; now is the time to start receiving and sending some. Here's a code snippet for receiving messages:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetIncomingMessage</span> msg;</pre>
<pre class="cl"><span class="cb3">while</span> ((msg = server.ReadMessage()) != <span class="cb3">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (msg.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.VerboseDebugMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DebugMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.WarningMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.ErrorMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(msg.ReadString());</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">default</span>:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(<span class="cb4">&quot;Unhandled type: &quot;</span> + msg.MessageType);</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; }</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; server.Recycle(msg);</pre>
<pre class="cl">}</pre>
</div>
<p>
So, lets dissect the above code. First we declare a NetIncomingMessage, which is the type of incoming messages. Then we read a message and handles it, looping back as long as there are messages to fetch. For each message we find, we switch on sometime called MessageType - it's a description what the message contains. In this code example we only catch messages of type VerboseDebugMessage, DebugMessage, WarningMessage and ErrorMessage. All those four types are emitted by the library to inform about various events. They all contains a single string, so we use the method ReadString() to extract a copy of that string and print it in the console.</p>
<p>
Reading data will increment the internal message pointer so you can read subsequent data using the Read*() methods.</p>
<p>
For all other message type we just print that it's currently unhandled.</p>
<p>
Finally, we recycle the message after we're done with it - this will enable the library to reuse the object and create less garbage.</p>
<p>
Sending messages are even easier:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetOutgoingMessage</span> sendMsg = server.CreateMessage();</pre>
<pre class="cl">sendMsg.Write(<span class="cb4">&quot;Hello&quot;</span>);</pre>
<pre class="cl">sendMsg.Write(42);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">server.SendMessage(sendMsg, recipient, <span class="cb2">NetDeliveryMethod</span>.ReliableOrdered);</pre>
</div>
<p>
The above code first creates a new message, or uses a recycled message, which is why it's not possible to just create a message using new(). It then writes a string ("Hello") and an integer (System.Int32, 4 bytes in size) to the message.</p>
<p>
Then the message is sent using the SendMessage() method. The first argument is the message to send, the second argument is the recipient connection - which we'll not go into detail about just yet - and the third argument are HOW to deliver the message, or rather how to behave if network conditions are bad and a packet gets lost, duplicated or reordered.</p>
<p>
There are five delivery methods available:</p>
<div class="cf">
<table>
<tr>
<td valign="top">
<b>Unreliable</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is just UDP. Messages can be lost, received more than once and messages sent after other messages may be received before them.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>UnreliableSequenced</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
Using this delivery method messages can still be lost; but you're protected against duplicated messages and if a message arrives late; that is, if a message sent after this one has already been received - it will be dropped. This means you will never receive "older" data than what you already have received.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>ReliableUnordered</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This delivery method ensures that every message sent will be received eventually. It does not however guarantee what order they will be received; late messages may be delivered before older ones.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>ReliableSequenced</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This delivery method is similar to UnreliableSequenced; except that is guarantees that SOME messages will be received - if you only send one message - it will be received. If you sent two messages quickly, and they get reordered in transit, only the newest message will be received - but at least ONE of them will be received guaranteed.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top"><b>ReliableOrdered</b></td>
<td>&nbsp;</td>
<td valign="top">
This delivery method guarantees that messages will always be received in the exact order they were sent.
</td>
</tr>
</table>
</div>
<p>
Here's how to read and decode the message above:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetIncomingMessage</span> incMsg = server.ReadMessage();</pre>
<pre class="cl"><span class="cb3">string</span> str = incMsg.ReadString();</pre>
<pre class="cl"><span class="cb3">int</span> a = incMsg.ReadInt32();</pre>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
namespace Lidgren.Network
{
/// <summary>
/// Interface for an encryption algorithm
/// </summary>
public interface INetEncryption
{
/// <summary>
/// Encrypt an outgoing message in place
/// </summary>
bool Encrypt(NetOutgoingMessage msg);
/// <summary>
/// Decrypt an incoming message in place
/// </summary>
bool Decrypt(NetIncomingMessage msg);
}
}

View File

@@ -1,163 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Lidgren.Network
{
/// <summary>
/// AES encryption
/// </summary>
public class NetAESEncryption : INetEncryption
{
private readonly byte[] m_key;
private readonly byte[] m_iv;
private readonly int m_bitSize;
private static readonly List<int> m_keysizes;
private static readonly List<int> m_blocksizes;
static NetAESEncryption()
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
List<int> temp = new List<int>();
foreach (KeySizes keysize in aes.LegalKeySizes)
{
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
{
if (!temp.Contains(i))
temp.Add(i);
if (i == keysize.MaxSize)
break;
}
}
m_keysizes = temp;
temp = new List<int>();
foreach (KeySizes keysize in aes.LegalBlockSizes)
{
for (int i = keysize.MinSize; i <= keysize.MaxSize; i += keysize.SkipSize)
{
if (!temp.Contains(i))
temp.Add(i);
if (i == keysize.MaxSize)
break;
}
}
m_blocksizes = temp;
}
/// <summary>
/// NetAESEncryption constructor
/// </summary>
public NetAESEncryption(byte[] key, byte[] iv)
{
if (!m_keysizes.Contains(key.Length * 8))
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
if (!m_blocksizes.Contains(iv.Length * 8))
throw new NetException(string.Format("Not a valid iv size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_blocksizes)));
m_key = key;
m_iv = iv;
m_bitSize = m_key.Length * 8;
}
/// <summary>
/// NetAESEncryption constructor
/// </summary>
public NetAESEncryption(string key, int bitsize)
{
if (!m_keysizes.Contains(bitsize))
throw new NetException(string.Format("Not a valid key size. (Valid values are: {0})", NetUtility.MakeCommaDelimitedList(m_keysizes)));
byte[] entropy = Encoding.UTF32.GetBytes(key);
// I know hardcoding salts is bad, but in this case I think it is acceptable.
HMACSHA512 hmacsha512 = new HMACSHA512(Convert.FromBase64String("i88NEiez3c50bHqr3YGasDc4p8jRrxJAaiRiqixpvp4XNAStP5YNoC2fXnWkURtkha6M8yY901Gj07IRVIRyGL=="));
hmacsha512.Initialize();
for (int i = 0; i < 1000; i++)
{
entropy = hmacsha512.ComputeHash(entropy);
}
int keylen = bitsize / 8;
m_key = new byte[keylen];
Buffer.BlockCopy(entropy, 0, m_key, 0, keylen);
m_iv = new byte[m_blocksizes[0] / 8];
Buffer.BlockCopy(entropy, entropy.Length - m_iv.Length - 1, m_iv, 0, m_iv.Length);
m_bitSize = bitsize;
}
/// <summary>
/// NetAESEncryption constructor
/// </summary>
public NetAESEncryption(string key)
: this(key, m_keysizes[0])
{
}
/// <summary>
/// Encrypt outgoing message
/// </summary>
public bool Encrypt(NetOutgoingMessage msg)
{
try
{
// nested usings are fun!
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
{
using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateEncryptor(m_key, m_iv))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
CryptoStreamMode.Write))
{
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
}
msg.m_data = memoryStream.ToArray();
}
}
}
}
catch
{
return false;
}
return true;
}
/// <summary>
/// Decrypt incoming message
/// </summary>
public bool Decrypt(NetIncomingMessage msg)
{
try
{
// nested usings are fun!
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider { KeySize = m_bitSize, Mode = CipherMode.CBC })
{
using (ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateDecryptor(m_key, m_iv))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform,
CryptoStreamMode.Write))
{
cryptoStream.Write(msg.m_data, 0, msg.m_data.Length);
}
msg.m_data = memoryStream.ToArray();
}
}
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -1,88 +0,0 @@
using System;
using System.Collections.Generic;
namespace Lidgren.Network
{
/// <summary>
/// Base for a non-threadsafe encryption class
/// </summary>
public abstract class NetBlockEncryptionBase : INetEncryption
{
// temporary space for one block to avoid reallocating every time
private byte[] m_tmp;
/// <summary>
/// Block size in bytes for this cipher
/// </summary>
public abstract int BlockSize { get; }
/// <summary>
/// NetBlockEncryptionBase constructor
/// </summary>
public NetBlockEncryptionBase()
{
m_tmp = new byte[BlockSize];
}
/// <summary>
/// Encrypt am outgoing message with this algorithm; no writing can be done to the message after encryption, or message will be corrupted
/// </summary>
public bool Encrypt(NetOutgoingMessage msg)
{
int payloadBitLength = msg.LengthBits;
int numBytes = msg.LengthBytes;
int blockSize = BlockSize;
int numBlocks = (int)Math.Ceiling((double)numBytes / (double)blockSize);
int dstSize = numBlocks * blockSize;
msg.EnsureBufferSize(dstSize * 8 + (4 * 8)); // add 4 bytes for payload length at end
msg.LengthBits = dstSize * 8; // length will automatically adjust +4 bytes when payload length is written
for(int i=0;i<numBlocks;i++)
{
EncryptBlock(msg.m_data, (i * blockSize), m_tmp);
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
}
// add true payload length last
msg.Write((UInt32)payloadBitLength);
return true;
}
/// <summary>
/// Decrypt an incoming message encrypted with corresponding Encrypt
/// </summary>
/// <param name="msg">message to decrypt</param>
/// <returns>true if successful; false if failed</returns>
public bool Decrypt(NetIncomingMessage msg)
{
int numEncryptedBytes = msg.LengthBytes - 4; // last 4 bytes is true bit length
int blockSize = BlockSize;
int numBlocks = numEncryptedBytes / blockSize;
if (numBlocks * blockSize != numEncryptedBytes)
return false;
for (int i = 0; i < numBlocks; i++)
{
DecryptBlock(msg.m_data, (i * blockSize), m_tmp);
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
}
// read 32 bits of true payload length
uint realSize = NetBitWriter.ReadUInt32(msg.m_data, 32, (numEncryptedBytes * 8));
msg.m_bitLength = (int)realSize;
return true;
}
/// <summary>
/// Encrypt a block of bytes
/// </summary>
protected abstract void EncryptBlock(byte[] source, int sourceOffset, byte[] destination);
/// <summary>
/// Decrypt a block of bytes
/// </summary>
protected abstract void DecryptBlock(byte[] source, int sourceOffset, byte[] destination);
}
}

View File

@@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace Lidgren.Network
{
/// <summary>
/// Interface for an encryption algorithm
/// </summary>
public abstract class NetEncryption
{
/// <summary>
/// NetPeer
/// </summary>
protected NetPeer m_peer;
/// <summary>
/// Constructor
/// </summary>
public NetEncryption(NetPeer peer)
{
if (peer == null)
throw new NetException("Peer must not be null");
m_peer = peer;
}
public void SetKey(string str)
{
var bytes = System.Text.Encoding.ASCII.GetBytes(str);
SetKey(bytes, 0, bytes.Length);
}
public abstract void SetKey(byte[] data, int offset, int count);
/// <summary>
/// Encrypt an outgoing message in place
/// </summary>
public abstract bool Encrypt(NetOutgoingMessage msg);
/// <summary>
/// Decrypt an incoming message in place
/// </summary>
public abstract bool Decrypt(NetIncomingMessage msg);
}
}

View File

@@ -1,146 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Security.Cryptography;
using System.Text;
using System.Security;
namespace Lidgren.Network
{
/// <summary>
/// Methods to encrypt and decrypt data using the XTEA algorithm
/// </summary>
public sealed class NetXtea : NetBlockEncryptionBase
{
private const int c_blockSize = 8;
private const int c_keySize = 16;
private const int c_delta = unchecked((int)0x9E3779B9);
private readonly int m_numRounds;
private readonly uint[] m_sum0;
private readonly uint[] m_sum1;
/// <summary>
/// Gets the block size for this cipher
/// </summary>
public override int BlockSize { get { return c_blockSize; } }
/// <summary>
/// 16 byte key
/// </summary>
public NetXtea(byte[] key, int rounds)
{
if (key.Length < c_keySize)
throw new NetException("Key too short!");
m_numRounds = rounds;
m_sum0 = new uint[m_numRounds];
m_sum1 = new uint[m_numRounds];
uint[] tmp = new uint[8];
int num2;
int index = num2 = 0;
while (index < 4)
{
tmp[index] = BitConverter.ToUInt32(key, num2);
index++;
num2 += 4;
}
for (index = num2 = 0; index < 32; index++)
{
m_sum0[index] = ((uint)num2) + tmp[num2 & 3];
num2 += -1640531527;
m_sum1[index] = ((uint)num2) + tmp[(num2 >> 11) & 3];
}
}
/// <summary>
/// 16 byte key
/// </summary>
public NetXtea(byte[] key)
: this(key, 32)
{
}
/// <summary>
/// String to hash for key
/// </summary>
public NetXtea(string key)
: this(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key)), 32)
{
}
/// <summary>
/// Encrypts a block of bytes
/// </summary>
protected override void EncryptBlock(byte[] source, int sourceOffset, byte[] destination)
{
uint v0 = BytesToUInt(source, sourceOffset);
uint v1 = BytesToUInt(source, sourceOffset + 4);
for (int i = 0; i != m_numRounds; i++)
{
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ m_sum0[i];
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ m_sum1[i];
}
UIntToBytes(v0, destination, 0);
UIntToBytes(v1, destination, 0 + 4);
return;
}
/// <summary>
/// Decrypts a block of bytes
/// </summary>
protected override void DecryptBlock(byte[] source, int sourceOffset, byte[] destination)
{
// Pack bytes into integers
uint v0 = BytesToUInt(source, sourceOffset);
uint v1 = BytesToUInt(source, sourceOffset + 4);
for (int i = m_numRounds - 1; i >= 0; i--)
{
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ m_sum1[i];
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ m_sum0[i];
}
UIntToBytes(v0, destination, 0);
UIntToBytes(v1, destination, 0 + 4);
return;
}
private static uint BytesToUInt(byte[] bytes, int offset)
{
uint retval = (uint)(bytes[offset] << 24);
retval |= (uint)(bytes[++offset] << 16);
retval |= (uint)(bytes[++offset] << 8);
return (retval | bytes[++offset]);
}
private static void UIntToBytes(uint value, byte[] destination, int destinationOffset)
{
destination[destinationOffset++] = (byte)(value >> 24);
destination[destinationOffset++] = (byte)(value >> 16);
destination[destinationOffset++] = (byte)(value >> 8);
destination[destinationOffset++] = (byte)value;
}
}
}

View File

@@ -1,10 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>false</IsPackable>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
<SonarQubeExclude>true</SonarQubeExclude>
<DefineConstants Condition="'$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'netcoreapp3.1'">$(DefineConstants);HAS_FULL_SPAN</DefineConstants>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<DefaultItemExcludes>Lidgren.Network/**/*</DefaultItemExcludes>
<DefineConstants>$(DefineConstants);USE_RELEASE_STATISTICS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="Lidgren.Network\Lidgren.Network\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
</Project>

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Lidgren.Network
{
/// <summary>
/// Lidgren Network Library
/// </summary>
internal class NamespaceDoc
{
// <include file='_Namespace.xml' path='Documentation/*' />
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,172 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Text;
namespace Lidgren.Network
{
/// <summary>
/// Fixed size vector of booleans
/// </summary>
public sealed class NetBitVector
{
private readonly int m_capacity;
private readonly int[] m_data;
private int m_numBitsSet;
/// <summary>
/// Gets the number of bits/booleans stored in this vector
/// </summary>
public int Capacity { get { return m_capacity; } }
/// <summary>
/// NetBitVector constructor
/// </summary>
public NetBitVector(int bitsCapacity)
{
m_capacity = bitsCapacity;
m_data = new int[(bitsCapacity + 31) / 32];
}
/// <summary>
/// Returns true if all bits/booleans are set to zero/false
/// </summary>
public bool IsEmpty()
{
return (m_numBitsSet == 0);
}
/// <summary>
/// Returns the number of bits/booleans set to one/true
/// </summary>
/// <returns></returns>
public int Count()
{
return m_numBitsSet;
}
/// <summary>
/// Shift all bits one step down, cycling the first bit to the top
/// </summary>
public void RotateDown()
{
int lenMinusOne = m_data.Length - 1;
int firstBit = m_data[0] & 1;
for (int i = 0; i < lenMinusOne; i++)
m_data[i] = ((m_data[i] >> 1) & ~(1 << 31)) | m_data[i + 1] << 31;
int lastIndex = m_capacity - 1 - (32 * lenMinusOne);
// special handling of last int
int cur = m_data[lenMinusOne];
cur = cur >> 1;
cur |= firstBit << lastIndex;
m_data[lenMinusOne] = cur;
}
/// <summary>
/// Gets the first (lowest) index set to true
/// </summary>
public int GetFirstSetIndex()
{
int idx = 0;
int data = m_data[0];
while (data == 0)
{
idx++;
data = m_data[idx];
}
int a = 0;
while (((data >> a) & 1) == 0)
a++;
return (idx * 32) + a;
}
/// <summary>
/// Gets the bit/bool at the specified index
/// </summary>
public bool Get(int bitIndex)
{
NetException.Assert(bitIndex >= 0 && bitIndex < m_capacity);
return (m_data[bitIndex / 32] & (1 << (bitIndex % 32))) != 0;
}
/// <summary>
/// Sets or clears the bit/bool at the specified index
/// </summary>
public void Set(int bitIndex, bool value)
{
NetException.Assert(bitIndex >= 0 && bitIndex < m_capacity);
int idx = bitIndex / 32;
if (value)
{
if ((m_data[idx] & (1 << (bitIndex % 32))) == 0)
m_numBitsSet++;
m_data[idx] |= (1 << (bitIndex % 32));
}
else
{
if ((m_data[idx] & (1 << (bitIndex % 32))) != 0)
m_numBitsSet--;
m_data[idx] &= (~(1 << (bitIndex % 32)));
}
}
/// <summary>
/// Gets the bit/bool at the specified index
/// </summary>
[System.Runtime.CompilerServices.IndexerName("Bit")]
public bool this[int index]
{
get { return Get(index); }
set { Set(index, value); }
}
/// <summary>
/// Sets all bits/booleans to zero/false
/// </summary>
public void Clear()
{
Array.Clear(m_data, 0, m_data.Length);
m_numBitsSet = 0;
NetException.Assert(this.IsEmpty());
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
StringBuilder bdr = new StringBuilder(m_capacity + 2);
bdr.Append('[');
for (int i = 0; i < m_capacity; i++)
bdr.Append(Get(m_capacity - i - 1) ? '1' : '0');
bdr.Append(']');
return bdr.ToString();
}
}
}

View File

@@ -1,504 +0,0 @@
//#define UNSAFE
//#define BIGENDIAN
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Helper class for NetBuffer to write/read bits
/// </summary>
public static class NetBitWriter
{
/// <summary>
/// Read 1-8 bits from a buffer into a byte
/// </summary>
public static byte ReadByte(byte[] fromBuffer, int numberOfBits, int readBitOffset)
{
NetException.Assert(((numberOfBits > 0) && (numberOfBits < 9)), "Read() can only read between 1 and 8 bits");
int bytePtr = readBitOffset >> 3;
int startReadAtIndex = readBitOffset - (bytePtr * 8);
if (startReadAtIndex == 0 && numberOfBits == 8)
return fromBuffer[bytePtr];
// mask away unused bits lower than (right of) relevant bits in first byte
byte returnValue = (byte)(fromBuffer[bytePtr] >> startReadAtIndex);
int numberOfBitsInSecondByte = numberOfBits - (8 - startReadAtIndex);
if (numberOfBitsInSecondByte < 1)
{
// we don't need to read from the second byte, but we DO need
// to mask away unused bits higher than (left of) relevant bits
return (byte)(returnValue & (255 >> (8 - numberOfBits)));
}
byte second = fromBuffer[bytePtr + 1];
// mask away unused bits higher than (left of) relevant bits in second byte
second &= (byte)(255 >> (8 - numberOfBitsInSecondByte));
return (byte)(returnValue | (byte)(second << (numberOfBits - numberOfBitsInSecondByte)));
}
/// <summary>
/// Read several bytes from a buffer
/// </summary>
public static void ReadBytes(byte[] fromBuffer, int numberOfBytes, int readBitOffset, byte[] destination, int destinationByteOffset)
{
int readPtr = readBitOffset >> 3;
int startReadAtIndex = readBitOffset - (readPtr * 8);
if (startReadAtIndex == 0)
{
Buffer.BlockCopy(fromBuffer, readPtr, destination, destinationByteOffset, numberOfBytes);
return;
}
int secondPartLen = 8 - startReadAtIndex;
int secondMask = 255 >> secondPartLen;
for (int i = 0; i < numberOfBytes; i++)
{
// mask away unused bits lower than (right of) relevant bits in byte
int b = fromBuffer[readPtr] >> startReadAtIndex;
readPtr++;
// mask away unused bits higher than (left of) relevant bits in second byte
int second = fromBuffer[readPtr] & secondMask;
destination[destinationByteOffset++] = (byte)(b | (second << secondPartLen));
}
return;
}
/// <summary>
/// Write a byte consisting of 1-8 bits to a buffer; assumes buffer is previously allocated
/// </summary>
public static void WriteByte(byte source, int numberOfBits, byte[] destination, int destBitOffset)
{
NetException.Assert(((numberOfBits >= 1) && (numberOfBits <= 8)), "Must write between 1 and 8 bits!");
// mask out unwanted bits in the source
byte isrc = (byte)(source & (0x000000FF >> (8 - numberOfBits)));
int bytePtr = destBitOffset >> 3;
int localBitLen = (destBitOffset % 8);
if (localBitLen == 0)
{
destination[bytePtr] = (byte)isrc;
return;
}
//destination[bytePtr] &= (byte)(255 >> (8 - localBitLen)); // clear before writing
//destination[bytePtr] |= (byte)(isrc << localBitLen); // write first half
destination[bytePtr] = (byte)(
(uint)(destination[bytePtr] & (255 >> (8 - localBitLen))) |
(uint)(isrc << localBitLen)
);
// need write into next byte?
if (localBitLen + numberOfBits > 8)
{
//destination[bytePtr + 1] &= (byte)(255 << localBitLen); // clear before writing
//destination[bytePtr + 1] |= (byte)(isrc >> (8 - localBitLen)); // write second half
destination[bytePtr + 1] = (byte)(
(uint)(destination[bytePtr + 1] & (255 << localBitLen)) |
(uint)(isrc >> (8 - localBitLen))
);
}
return;
}
/// <summary>
/// Write several whole bytes
/// </summary>
public static void WriteBytes(byte[] source, int sourceByteOffset, int numberOfBytes, byte[] destination, int destBitOffset)
{
int dstBytePtr = destBitOffset >> 3;
int firstPartLen = (destBitOffset % 8);
if (firstPartLen == 0)
{
Buffer.BlockCopy(source, sourceByteOffset, destination, dstBytePtr, numberOfBytes);
return;
}
int lastPartLen = 8 - firstPartLen;
for (int i = 0; i < numberOfBytes; i++)
{
byte src = source[sourceByteOffset + i];
// write last part of this byte
destination[dstBytePtr] &= (byte)(255 >> lastPartLen); // clear before writing
destination[dstBytePtr] |= (byte)(src << firstPartLen); // write first half
dstBytePtr++;
// write first part of next byte
destination[dstBytePtr] &= (byte)(255 << firstPartLen); // clear before writing
destination[dstBytePtr] |= (byte)(src >> lastPartLen); // write second half
}
return;
}
/// <summary>
/// Reads an unsigned 16 bit integer
/// </summary>
[CLSCompliant(false)]
#if UNSAFE
public static unsafe ushort ReadUInt16(byte[] fromBuffer, int numberOfBits, int readBitOffset)
{
Debug.Assert(((numberOfBits > 0) && (numberOfBits <= 16)), "ReadUInt16() can only read between 1 and 16 bits");
if (numberOfBits == 16 && ((readBitOffset % 8) == 0))
{
fixed (byte* ptr = &(fromBuffer[readBitOffset / 8]))
{
return *(((ushort*)ptr));
}
}
#else
public static ushort ReadUInt16(byte[] fromBuffer, int numberOfBits, int readBitOffset)
{
Debug.Assert(((numberOfBits > 0) && (numberOfBits <= 16)), "ReadUInt16() can only read between 1 and 16 bits");
#endif
ushort returnValue;
if (numberOfBits <= 8)
{
returnValue = ReadByte(fromBuffer, numberOfBits, readBitOffset);
return returnValue;
}
returnValue = ReadByte(fromBuffer, 8, readBitOffset);
numberOfBits -= 8;
readBitOffset += 8;
if (numberOfBits <= 8)
{
returnValue |= (ushort)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 8);
}
#if BIGENDIAN
// reorder bytes
uint retVal = returnValue;
retVal = ((retVal & 0x0000ff00) >> 8) | ((retVal & 0x000000ff) << 8);
return (ushort)retVal;
#else
return returnValue;
#endif
}
/// <summary>
/// Reads the specified number of bits into an UInt32
/// </summary>
[CLSCompliant(false)]
#if UNSAFE
public static unsafe uint ReadUInt32(byte[] fromBuffer, int numberOfBits, int readBitOffset)
{
NetException.Assert(((numberOfBits > 0) && (numberOfBits <= 32)), "ReadUInt32() can only read between 1 and 32 bits");
if (numberOfBits == 32 && ((readBitOffset % 8) == 0))
{
fixed (byte* ptr = &(fromBuffer[readBitOffset / 8]))
{
return *(((uint*)ptr));
}
}
#else
public static uint ReadUInt32(byte[] fromBuffer, int numberOfBits, int readBitOffset)
{
NetException.Assert(((numberOfBits > 0) && (numberOfBits <= 32)), "ReadUInt32() can only read between 1 and 32 bits");
#endif
uint returnValue;
if (numberOfBits <= 8)
{
returnValue = ReadByte(fromBuffer, numberOfBits, readBitOffset);
return returnValue;
}
returnValue = ReadByte(fromBuffer, 8, readBitOffset);
numberOfBits -= 8;
readBitOffset += 8;
if (numberOfBits <= 8)
{
returnValue |= (uint)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 8);
return returnValue;
}
returnValue |= (uint)(ReadByte(fromBuffer, 8, readBitOffset) << 8);
numberOfBits -= 8;
readBitOffset += 8;
if (numberOfBits <= 8)
{
uint r = ReadByte(fromBuffer, numberOfBits, readBitOffset);
r <<= 16;
returnValue |= r;
return returnValue;
}
returnValue |= (uint)(ReadByte(fromBuffer, 8, readBitOffset) << 16);
numberOfBits -= 8;
readBitOffset += 8;
returnValue |= (uint)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 24);
#if BIGENDIAN
// reorder bytes
return
((returnValue & 0xff000000) >> 24) |
((returnValue & 0x00ff0000) >> 8) |
((returnValue & 0x0000ff00) << 8) |
((returnValue & 0x000000ff) << 24);
#else
return returnValue;
#endif
}
//[CLSCompliant(false)]
//public static ulong ReadUInt64(byte[] fromBuffer, int numberOfBits, int readBitOffset)
/// <summary>
/// Writes un unsigned 16 bit integer
/// </summary>
[CLSCompliant(false)]
public static int WriteUInt16(ushort source, int numberOfBits, byte[] destination, int destinationBitOffset)
{
#if BIGENDIAN
// reorder bytes
uint intSource = source;
intSource = ((intSource & 0x0000ff00) >> 8) | ((intSource & 0x000000ff) << 8);
source = (ushort)intSource;
#endif
int returnValue = destinationBitOffset + numberOfBits;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
return returnValue;
}
/// <summary>
/// Writes the specified number of bits into a byte array
/// </summary>
[CLSCompliant(false)]
public static int WriteUInt32(uint source, int numberOfBits, byte[] destination, int destinationBitOffset)
{
#if BIGENDIAN
// reorder bytes
source = ((source & 0xff000000) >> 24) |
((source & 0x00ff0000) >> 8) |
((source & 0x0000ff00) << 8) |
((source & 0x000000ff) << 24);
#endif
int returnValue = destinationBitOffset + numberOfBits;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
NetBitWriter.WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
/// <summary>
/// Writes the specified number of bits into a byte array
/// </summary>
[CLSCompliant(false)]
public static int WriteUInt64(ulong source, int numberOfBits, byte[] destination, int destinationBitOffset)
{
#if BIGENDIAN
source = ((source & 0xff00000000000000L) >> 56) |
((source & 0x00ff000000000000L) >> 40) |
((source & 0x0000ff0000000000L) >> 24) |
((source & 0x000000ff00000000L) >> 8) |
((source & 0x00000000ff000000L) << 8) |
((source & 0x0000000000ff0000L) << 24) |
((source & 0x000000000000ff00L) << 40) |
((source & 0x00000000000000ffL) << 56);
#endif
int returnValue = destinationBitOffset + numberOfBits;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 24), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 32), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 32), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 40), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 40), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 48), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 48), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
if (numberOfBits <= 8)
{
NetBitWriter.WriteByte((byte)(source >> 56), numberOfBits, destination, destinationBitOffset);
return returnValue;
}
NetBitWriter.WriteByte((byte)(source >> 56), 8, destination, destinationBitOffset);
destinationBitOffset += 8;
numberOfBits -= 8;
return returnValue;
}
//
// Variable size
//
/// <summary>
/// Write Base128 encoded variable sized unsigned integer
/// </summary>
/// <returns>number of bytes written</returns>
[CLSCompliant(false)]
public static int WriteVariableUInt32(byte[] intoBuffer, int offset, uint value)
{
int retval = 0;
uint num1 = (uint)value;
while (num1 >= 0x80)
{
intoBuffer[offset + retval] = (byte)(num1 | 0x80);
num1 = num1 >> 7;
retval++;
}
intoBuffer[offset + retval] = (byte)num1;
return retval + 1;
}
/// <summary>
/// Reads a UInt32 written using WriteUnsignedVarInt(); will increment offset!
/// </summary>
[CLSCompliant(false)]
public static uint ReadVariableUInt32(byte[] buffer, ref int offset)
{
int num1 = 0;
int num2 = 0;
while (true)
{
if (num2 == 0x23)
throw new FormatException("Bad 7-bit encoded integer");
byte num3 = buffer[offset++];
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
num2 += 7;
if ((num3 & 0x80) == 0)
return (uint)num1;
}
}
}
}

View File

@@ -1,311 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.Net;
namespace Lidgren.Network
{
public partial class NetBuffer
{
/// <summary>
/// Gets the internal data buffer
/// </summary>
public byte[] PeekDataBuffer() { return m_data; }
//
// 1 bit
//
/// <summary>
/// Reads a 1-bit Boolean without advancing the read pointer
/// </summary>
public bool PeekBoolean()
{
NetException.Assert(m_bitLength - m_readPosition >= 1, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 1, m_readPosition);
return (retval > 0 ? true : false);
}
//
// 8 bit
//
/// <summary>
/// Reads a Byte without advancing the read pointer
/// </summary>
public byte PeekByte()
{
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
return retval;
}
/// <summary>
/// Reads an SByte without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public sbyte PeekSByte()
{
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
return (sbyte)retval;
}
/// <summary>
/// Reads the specified number of bits into a Byte without advancing the read pointer
/// </summary>
public byte PeekByte(int numberOfBits)
{
byte retval = NetBitWriter.ReadByte(m_data, numberOfBits, m_readPosition);
return retval;
}
/// <summary>
/// Reads the specified number of bytes without advancing the read pointer
/// </summary>
public byte[] PeekBytes(int numberOfBytes)
{
NetException.Assert(m_bitLength - m_readPosition >= (numberOfBytes * 8), c_readOverflowError);
byte[] retval = new byte[numberOfBytes];
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, retval, 0);
return retval;
}
/// <summary>
/// Reads the specified number of bytes without advancing the read pointer
/// </summary>
public void PeekBytes(byte[] into, int offset, int numberOfBytes)
{
NetException.Assert(m_bitLength - m_readPosition >= (numberOfBytes * 8), c_readOverflowError);
NetException.Assert(offset + numberOfBytes <= into.Length);
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, into, offset);
return;
}
//
// 16 bit
//
/// <summary>
/// Reads an Int16 without advancing the read pointer
/// </summary>
public Int16 PeekInt16()
{
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
return (short)retval;
}
/// <summary>
/// Reads a UInt16 without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public UInt16 PeekUInt16()
{
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
return (ushort)retval;
}
//
// 32 bit
//
/// <summary>
/// Reads an Int32 without advancing the read pointer
/// </summary>
public Int32 PeekInt32()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
return (Int32)retval;
}
/// <summary>
/// Reads the specified number of bits into an Int32 without advancing the read pointer
/// </summary>
public Int32 PeekInt32(int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 32), "ReadInt() can only read between 1 and 32 bits");
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
if (numberOfBits == 32)
return (int)retval;
int signBit = 1 << (numberOfBits - 1);
if ((retval & signBit) == 0)
return (int)retval; // positive
// negative
unchecked
{
uint mask = ((uint)-1) >> (33 - numberOfBits);
uint tmp = (retval & mask) + 1;
return -((int)tmp);
}
}
/// <summary>
/// Reads a UInt32 without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public UInt32 PeekUInt32()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
return retval;
}
/// <summary>
/// Reads the specified number of bits into a UInt32 without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public UInt32 PeekUInt32(int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 32), "ReadUInt() can only read between 1 and 32 bits");
UInt32 retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
return retval;
}
//
// 64 bit
//
/// <summary>
/// Reads a UInt64 without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public UInt64 PeekUInt64()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
ulong low = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
ulong high = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition + 32);
ulong retval = low + (high << 32);
return retval;
}
/// <summary>
/// Reads an Int64 without advancing the read pointer
/// </summary>
public Int64 PeekInt64()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
unchecked
{
ulong retval = PeekUInt64();
long longRetval = (long)retval;
return longRetval;
}
}
/// <summary>
/// Reads the specified number of bits into an UInt64 without advancing the read pointer
/// </summary>
[CLSCompliant(false)]
public UInt64 PeekUInt64(int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 64), "ReadUInt() can only read between 1 and 64 bits");
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
ulong retval;
if (numberOfBits <= 32)
{
retval = (ulong)NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
}
else
{
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
retval |= NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition) << 32;
}
return retval;
}
/// <summary>
/// Reads the specified number of bits into an Int64 without advancing the read pointer
/// </summary>
public Int64 PeekInt64(int numberOfBits)
{
NetException.Assert(((numberOfBits > 0) && (numberOfBits < 65)), "ReadInt64(bits) can only read between 1 and 64 bits");
return (long)PeekUInt64(numberOfBits);
}
//
// Floating point
//
/// <summary>
/// Reads a 32-bit Single without advancing the read pointer
/// </summary>
public float PeekFloat()
{
return PeekSingle();
}
/// <summary>
/// Reads a 32-bit Single without advancing the read pointer
/// </summary>
public float PeekSingle()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
if ((m_readPosition & 7) == 0) // read directly
{
float retval = BitConverter.ToSingle(m_data, m_readPosition >> 3);
return retval;
}
byte[] bytes = PeekBytes(4);
return BitConverter.ToSingle(bytes, 0);
}
/// <summary>
/// Reads a 64-bit Double without advancing the read pointer
/// </summary>
public double PeekDouble()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
if ((m_readPosition & 7) == 0) // read directly
{
// read directly
double retval = BitConverter.ToDouble(m_data, m_readPosition >> 3);
return retval;
}
byte[] bytes = PeekBytes(8);
return BitConverter.ToDouble(bytes, 0);
}
/// <summary>
/// Reads a string without advancing the read pointer
/// </summary>
public string PeekString()
{
int wasReadPosition = m_readPosition;
string retval = ReadString();
m_readPosition = wasReadPosition;
return retval;
}
}
}

View File

@@ -1,103 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Reflection;
namespace Lidgren.Network
{
public partial class NetBuffer
{
/// <summary>
/// Reads all public and private declared instance fields of the object in alphabetical order using reflection
/// </summary>
public void ReadAllFields(object target)
{
ReadAllFields(target, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
}
/// <summary>
/// Reads all fields with the specified binding of the object in alphabetical order using reflection
/// </summary>
public void ReadAllFields(object target, BindingFlags flags)
{
if (target == null)
return;
Type tp = target.GetType();
FieldInfo[] fields = tp.GetFields(flags);
NetUtility.SortMembersList(fields);
foreach (FieldInfo fi in fields)
{
object value;
// find read method
MethodInfo readMethod;
if (s_readMethods.TryGetValue(fi.FieldType, out readMethod))
{
// read value
value = readMethod.Invoke(this, null);
// set the value
fi.SetValue(target, value);
}
}
}
/// <summary>
/// Reads all public and private declared instance fields of the object in alphabetical order using reflection
/// </summary>
public void ReadAllProperties(object target)
{
ReadAllProperties(target, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
}
/// <summary>
/// Reads all fields with the specified binding of the object in alphabetical order using reflection
/// </summary>
public void ReadAllProperties(object target, BindingFlags flags)
{
if (target == null)
throw new ArgumentNullException("target");
if (target == null)
return;
Type tp = target.GetType();
PropertyInfo[] fields = tp.GetProperties(flags);
NetUtility.SortMembersList(fields);
foreach (PropertyInfo fi in fields)
{
object value;
// find read method
MethodInfo readMethod;
if (s_readMethods.TryGetValue(fi.PropertyType, out readMethod))
{
// read value
value = readMethod.Invoke(this, null);
// set the value
MethodInfo setMethod = fi.GetSetMethod((flags & BindingFlags.NonPublic) == BindingFlags.NonPublic);
setMethod.Invoke(target, new object[] { value });
}
}
}
}
}

View File

@@ -1,653 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Net;
namespace Lidgren.Network
{
/// <summary>
/// Base class for NetIncomingMessage and NetOutgoingMessage
/// </summary>
public partial class NetBuffer
{
private const string c_readOverflowError = "Trying to read past the buffer size - likely caused by mismatching Write/Reads, different size or order.";
/// <summary>
/// Reads a boolean value (stored as a single bit) written using Write(bool)
/// </summary>
public bool ReadBoolean()
{
NetException.Assert(m_bitLength - m_readPosition >= 1, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 1, m_readPosition);
m_readPosition += 1;
return (retval > 0 ? true : false);
}
/// <summary>
/// Reads a byte
/// </summary>
public byte ReadByte()
{
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
m_readPosition += 8;
return retval;
}
/// <summary>
/// Reads a byte and returns true or false for success
/// </summary>
public bool ReadByte(out byte result)
{
if (m_bitLength - m_readPosition < 8)
{
result = 0;
return false;
}
result = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
m_readPosition += 8;
return true;
}
/// <summary>
/// Reads a signed byte
/// </summary>
[CLSCompliant(false)]
public sbyte ReadSByte()
{
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
m_readPosition += 8;
return (sbyte)retval;
}
/// <summary>
/// Reads 1 to 8 bits into a byte
/// </summary>
public byte ReadByte(int numberOfBits)
{
NetException.Assert(numberOfBits > 0 && numberOfBits <= 8, "ReadByte(bits) can only read between 1 and 8 bits");
byte retval = NetBitWriter.ReadByte(m_data, numberOfBits, m_readPosition);
m_readPosition += numberOfBits;
return retval;
}
/// <summary>
/// Reads the specified number of bytes
/// </summary>
public byte[] ReadBytes(int numberOfBytes)
{
NetException.Assert(m_bitLength - m_readPosition + 7 >= (numberOfBytes * 8), c_readOverflowError);
byte[] retval = new byte[numberOfBytes];
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, retval, 0);
m_readPosition += (8 * numberOfBytes);
return retval;
}
/// <summary>
/// Reads the specified number of bytes and returns true for success
/// </summary>
public bool ReadBytes(int numberOfBytes, out byte[] result)
{
if (m_bitLength - m_readPosition + 7 < (numberOfBytes * 8))
{
result = null;
return false;
}
result = new byte[numberOfBytes];
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, result, 0);
m_readPosition += (8 * numberOfBytes);
return true;
}
/// <summary>
/// Reads the specified number of bytes into a preallocated array
/// </summary>
/// <param name="into">The destination array</param>
/// <param name="offset">The offset where to start writing in the destination array</param>
/// <param name="numberOfBytes">The number of bytes to read</param>
public void ReadBytes(byte[] into, int offset, int numberOfBytes)
{
NetException.Assert(m_bitLength - m_readPosition + 7 >= (numberOfBytes * 8), c_readOverflowError);
NetException.Assert(offset + numberOfBytes <= into.Length);
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, into, offset);
m_readPosition += (8 * numberOfBytes);
return;
}
/// <summary>
/// Reads the specified number of bits into a preallocated array
/// </summary>
/// <param name="into">The destination array</param>
/// <param name="offset">The offset where to start writing in the destination array</param>
/// <param name="numberOfBits">The number of bits to read</param>
public void ReadBits(byte[] into, int offset, int numberOfBits)
{
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
NetException.Assert(offset + NetUtility.BytesToHoldBits(numberOfBits) <= into.Length);
int numberOfWholeBytes = numberOfBits / 8;
int extraBits = numberOfBits - (numberOfWholeBytes * 8);
NetBitWriter.ReadBytes(m_data, numberOfWholeBytes, m_readPosition, into, offset);
m_readPosition += (8 * numberOfWholeBytes);
if (extraBits > 0)
into[offset + numberOfWholeBytes] = ReadByte(extraBits);
return;
}
/// <summary>
/// Reads a 16 bit signed integer written using Write(Int16)
/// </summary>
public Int16 ReadInt16()
{
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
m_readPosition += 16;
return (short)retval;
}
/// <summary>
/// Reads a 16 bit unsigned integer written using Write(UInt16)
/// </summary>
[CLSCompliant(false)]
public UInt16 ReadUInt16()
{
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
m_readPosition += 16;
return (ushort)retval;
}
/// <summary>
/// Reads a 32 bit signed integer written using Write(Int32)
/// </summary>
public Int32 ReadInt32()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
m_readPosition += 32;
return (Int32)retval;
}
/// <summary>
/// Reads a 32 bit signed integer written using Write(Int32)
/// </summary>
[CLSCompliant(false)]
public bool ReadInt32(out Int32 result)
{
if (m_bitLength - m_readPosition < 32)
{
result = 0;
return false;
}
result = (Int32)NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
m_readPosition += 32;
return true;
}
/// <summary>
/// Reads a signed integer stored in 1 to 32 bits, written using Write(Int32, Int32)
/// </summary>
public Int32 ReadInt32(int numberOfBits)
{
NetException.Assert(numberOfBits > 0 && numberOfBits <= 32, "ReadInt32(bits) can only read between 1 and 32 bits");
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
m_readPosition += numberOfBits;
if (numberOfBits == 32)
return (int)retval;
int signBit = 1 << (numberOfBits - 1);
if ((retval & signBit) == 0)
return (int)retval; // positive
// negative
unchecked
{
uint mask = ((uint)-1) >> (33 - numberOfBits);
uint tmp = (retval & mask) + 1;
return -((int)tmp);
}
}
/// <summary>
/// Reads an 32 bit unsigned integer written using Write(UInt32)
/// </summary>
[CLSCompliant(false)]
public UInt32 ReadUInt32()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
m_readPosition += 32;
return retval;
}
/// <summary>
/// Reads an 32 bit unsigned integer written using Write(UInt32) and returns true for success
/// </summary>
[CLSCompliant(false)]
public bool ReadUInt32(out UInt32 result)
{
if (m_bitLength - m_readPosition < 32)
{
result = 0;
return false;
}
result = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
m_readPosition += 32;
return true;
}
/// <summary>
/// Reads an unsigned integer stored in 1 to 32 bits, written using Write(UInt32, Int32)
/// </summary>
[CLSCompliant(false)]
public UInt32 ReadUInt32(int numberOfBits)
{
NetException.Assert(numberOfBits > 0 && numberOfBits <= 32, "ReadUInt32(bits) can only read between 1 and 32 bits");
UInt32 retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
m_readPosition += numberOfBits;
return retval;
}
/// <summary>
/// Reads a 64 bit unsigned integer written using Write(UInt64)
/// </summary>
[CLSCompliant(false)]
public UInt64 ReadUInt64()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
ulong low = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
m_readPosition += 32;
ulong high = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
ulong retval = low + (high << 32);
m_readPosition += 32;
return retval;
}
/// <summary>
/// Reads a 64 bit signed integer written using Write(Int64)
/// </summary>
public Int64 ReadInt64()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
unchecked
{
ulong retval = ReadUInt64();
long longRetval = (long)retval;
return longRetval;
}
}
/// <summary>
/// Reads an unsigned integer stored in 1 to 64 bits, written using Write(UInt64, Int32)
/// </summary>
[CLSCompliant(false)]
public UInt64 ReadUInt64(int numberOfBits)
{
NetException.Assert(numberOfBits > 0 && numberOfBits <= 64, "ReadUInt64(bits) can only read between 1 and 64 bits");
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
ulong retval;
if (numberOfBits <= 32)
{
retval = (ulong)NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
}
else
{
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
retval |= NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition) << 32;
}
m_readPosition += numberOfBits;
return retval;
}
/// <summary>
/// Reads a signed integer stored in 1 to 64 bits, written using Write(Int64, Int32)
/// </summary>
public Int64 ReadInt64(int numberOfBits)
{
NetException.Assert(((numberOfBits > 0) && (numberOfBits <= 64)), "ReadInt64(bits) can only read between 1 and 64 bits");
return (long)ReadUInt64(numberOfBits);
}
/// <summary>
/// Reads a 32 bit floating point value written using Write(Single)
/// </summary>
public float ReadFloat()
{
return ReadSingle();
}
/// <summary>
/// Reads a 32 bit floating point value written using Write(Single)
/// </summary>
public float ReadSingle()
{
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
if ((m_readPosition & 7) == 0) // read directly
{
float retval = BitConverter.ToSingle(m_data, m_readPosition >> 3);
m_readPosition += 32;
return retval;
}
byte[] bytes = ReadBytes(4);
return BitConverter.ToSingle(bytes, 0);
}
/// <summary>
/// Reads a 32 bit floating point value written using Write(Single)
/// </summary>
public bool ReadSingle(out float result)
{
if (m_bitLength - m_readPosition < 32)
{
result = 0.0f;
return false;
}
if ((m_readPosition & 7) == 0) // read directly
{
result = BitConverter.ToSingle(m_data, m_readPosition >> 3);
m_readPosition += 32;
return true;
}
byte[] bytes = ReadBytes(4);
result = BitConverter.ToSingle(bytes, 0);
return true;
}
/// <summary>
/// Reads a 64 bit floating point value written using Write(Double)
/// </summary>
public double ReadDouble()
{
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
if ((m_readPosition & 7) == 0) // read directly
{
// read directly
double retval = BitConverter.ToDouble(m_data, m_readPosition >> 3);
m_readPosition += 64;
return retval;
}
byte[] bytes = ReadBytes(8);
return BitConverter.ToDouble(bytes, 0);
}
//
// Variable bit count
//
/// <summary>
/// Reads a variable sized UInt32 written using WriteVariableUInt32()
/// </summary>
[CLSCompliant(false)]
public uint ReadVariableUInt32()
{
int num1 = 0;
int num2 = 0;
while (true)
{
byte num3 = this.ReadByte();
num1 |= (num3 & 0x7f) << num2;
num2 += 7;
if ((num3 & 0x80) == 0)
return (uint)num1;
}
}
/// <summary>
/// Reads a variable sized UInt32 written using WriteVariableUInt32() and returns true for success
/// </summary>
[CLSCompliant(false)]
public bool ReadVariableUInt32(out uint result)
{
int num1 = 0;
int num2 = 0;
while (true)
{
byte num3;
if (ReadByte(out num3) == false)
{
result = 0;
return false;
}
num1 |= (num3 & 0x7f) << num2;
num2 += 7;
if ((num3 & 0x80) == 0)
{
result = (uint)num1;
return true;
}
}
}
/// <summary>
/// Reads a variable sized Int32 written using WriteVariableInt32()
/// </summary>
public int ReadVariableInt32()
{
uint n = ReadVariableUInt32();
return (int)(n >> 1) ^ -(int)(n & 1); // decode zigzag
}
/// <summary>
/// Reads a variable sized Int64 written using WriteVariableInt64()
/// </summary>
public Int64 ReadVariableInt64()
{
UInt64 n = ReadVariableUInt64();
return (Int64)(n >> 1) ^ -(long)(n & 1); // decode zigzag
}
/// <summary>
/// Reads a variable sized UInt32 written using WriteVariableInt64()
/// </summary>
[CLSCompliant(false)]
public UInt64 ReadVariableUInt64()
{
UInt64 num1 = 0;
int num2 = 0;
while (true)
{
byte num3 = this.ReadByte();
num1 |= ((UInt64)num3 & 0x7f) << num2;
num2 += 7;
if ((num3 & 0x80) == 0)
return num1;
}
}
/// <summary>
/// Reads a 32 bit floating point value written using WriteSignedSingle()
/// </summary>
/// <param name="numberOfBits">The number of bits used when writing the value</param>
/// <returns>A floating point value larger or equal to -1 and smaller or equal to 1</returns>
public float ReadSignedSingle(int numberOfBits)
{
uint encodedVal = ReadUInt32(numberOfBits);
int maxVal = (1 << numberOfBits) - 1;
return ((float)(encodedVal + 1) / (float)(maxVal + 1) - 0.5f) * 2.0f;
}
/// <summary>
/// Reads a 32 bit floating point value written using WriteUnitSingle()
/// </summary>
/// <param name="numberOfBits">The number of bits used when writing the value</param>
/// <returns>A floating point value larger or equal to 0 and smaller or equal to 1</returns>
public float ReadUnitSingle(int numberOfBits)
{
uint encodedVal = ReadUInt32(numberOfBits);
int maxVal = (1 << numberOfBits) - 1;
return (float)(encodedVal + 1) / (float)(maxVal + 1);
}
/// <summary>
/// Reads a 32 bit floating point value written using WriteRangedSingle()
/// </summary>
/// <param name="min">The minimum value used when writing the value</param>
/// <param name="max">The maximum value used when writing the value</param>
/// <param name="numberOfBits">The number of bits used when writing the value</param>
/// <returns>A floating point value larger or equal to MIN and smaller or equal to MAX</returns>
public float ReadRangedSingle(float min, float max, int numberOfBits)
{
float range = max - min;
int maxVal = (1 << numberOfBits) - 1;
float encodedVal = (float)ReadUInt32(numberOfBits);
float unit = encodedVal / (float)maxVal;
return min + (unit * range);
}
/// <summary>
/// Reads a 32 bit integer value written using WriteRangedInteger()
/// </summary>
/// <param name="min">The minimum value used when writing the value</param>
/// <param name="max">The maximum value used when writing the value</param>
/// <returns>A signed integer value larger or equal to MIN and smaller or equal to MAX</returns>
public int ReadRangedInteger(int min, int max)
{
uint range = (uint)(max - min);
int numBits = NetUtility.BitsToHoldUInt(range);
uint rvalue = ReadUInt32(numBits);
return (int)(min + rvalue);
}
/// <summary>
/// Reads a string written using Write(string)
/// </summary>
public string ReadString()
{
int byteLen = (int)ReadVariableUInt32();
if (byteLen == 0)
return String.Empty;
NetException.Assert(m_bitLength - m_readPosition >= (byteLen * 8), c_readOverflowError);
if ((m_readPosition & 7) == 0)
{
// read directly
string retval = System.Text.Encoding.UTF8.GetString(m_data, m_readPosition >> 3, byteLen);
m_readPosition += (8 * byteLen);
return retval;
}
byte[] bytes = ReadBytes(byteLen);
return System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
/// <summary>
/// Reads a string written using Write(string) and returns true for success
/// </summary>
public bool ReadString(out string result)
{
uint byteLen;
if (ReadVariableUInt32(out byteLen) == false)
{
result = String.Empty;
return false;
}
if (byteLen == 0)
{
result = String.Empty;
return true;
}
if (m_bitLength - m_readPosition < (byteLen * 8))
{
result = String.Empty;
return false;
}
if ((m_readPosition & 7) == 0)
{
// read directly
result = System.Text.Encoding.UTF8.GetString(m_data, m_readPosition >> 3, (int)byteLen);
m_readPosition += (8 * (int)byteLen);
return true;
}
byte[] bytes;
if (ReadBytes((int)byteLen, out bytes) == false)
{
result = String.Empty;
return false;
}
result = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
return true;
}
/// <summary>
/// Reads a value, in local time comparable to NetTime.Now, written using WriteTime() for the connection supplied
/// </summary>
public double ReadTime(NetConnection connection, bool highPrecision)
{
double remoteTime = (highPrecision ? ReadDouble() : (double)ReadSingle());
if (connection == null)
throw new NetException("Cannot call ReadTime() on message without a connected sender (ie. unconnected messages)");
// lets bypass NetConnection.GetLocalTime for speed
return remoteTime - connection.m_remoteTimeOffset;
}
/// <summary>
/// Reads a stored IPv4 endpoint description
/// </summary>
public IPEndPoint ReadIPEndPoint()
{
byte len = ReadByte();
byte[] addressBytes = ReadBytes(len);
int port = (int)ReadUInt16();
IPAddress address = new IPAddress(addressBytes);
return new IPEndPoint(address, port);
}
/// <summary>
/// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes.
/// </summary>
public void SkipPadBits()
{
m_readPosition = ((m_readPosition + 7) >> 3) * 8;
}
/// <summary>
/// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes.
/// </summary>
public void ReadPadBits()
{
m_readPosition = ((m_readPosition + 7) >> 3) * 8;
}
/// <summary>
/// Pads data with the specified number of bits.
/// </summary>
public void SkipPadBits(int numberOfBits)
{
m_readPosition += numberOfBits;
}
}
}

View File

@@ -1,91 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Reflection;
namespace Lidgren.Network
{
public partial class NetBuffer
{
/// <summary>
/// Writes all public and private declared instance fields of the object in alphabetical order using reflection
/// </summary>
public void WriteAllFields(object ob)
{
WriteAllFields(ob, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
}
/// <summary>
/// Writes all fields with specified binding in alphabetical order using reflection
/// </summary>
public void WriteAllFields(object ob, BindingFlags flags)
{
if (ob == null)
return;
Type tp = ob.GetType();
FieldInfo[] fields = tp.GetFields(flags);
NetUtility.SortMembersList(fields);
foreach (FieldInfo fi in fields)
{
object value = fi.GetValue(ob);
// find the appropriate Write method
MethodInfo writeMethod;
if (s_writeMethods.TryGetValue(fi.FieldType, out writeMethod))
writeMethod.Invoke(this, new object[] { value });
else
throw new NetException("Failed to find write method for type " + fi.FieldType);
}
}
/// <summary>
/// Writes all public and private declared instance properties of the object in alphabetical order using reflection
/// </summary>
public void WriteAllProperties(object ob)
{
WriteAllProperties(ob, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
}
/// <summary>
/// Writes all properties with specified binding in alphabetical order using reflection
/// </summary>
public void WriteAllProperties(object ob, BindingFlags flags)
{
if (ob == null)
return;
Type tp = ob.GetType();
PropertyInfo[] fields = tp.GetProperties(flags);
NetUtility.SortMembersList(fields);
foreach (PropertyInfo fi in fields)
{
MethodInfo getMethod = fi.GetGetMethod((flags & BindingFlags.NonPublic) == BindingFlags.NonPublic);
object value = getMethod.Invoke(ob, null);
// find the appropriate Write method
MethodInfo writeMethod;
if (s_writeMethods.TryGetValue(fi.PropertyType, out writeMethod))
writeMethod.Invoke(this, new object[] { value });
}
}
}
}

View File

@@ -1,637 +0,0 @@
//#define UNSAFE
//#define BIGENDIAN
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Text;
using System.Runtime.InteropServices;
namespace Lidgren.Network
{
/// <summary>
/// Utility struct for writing Singles
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct SingleUIntUnion
{
/// <summary>
/// Value as a 32 bit float
/// </summary>
[FieldOffset(0)]
public float SingleValue;
/// <summary>
/// Value as an unsigned 32 bit integer
/// </summary>
[FieldOffset(0)]
[CLSCompliant(false)]
public uint UIntValue;
}
public partial class NetBuffer
{
/// <summary>
/// Ensures the buffer can hold this number of bits
/// </summary>
public void EnsureBufferSize(int numberOfBits)
{
int byteLen = ((numberOfBits + 7) >> 3);
if (m_data == null)
{
m_data = new byte[byteLen + c_overAllocateAmount];
return;
}
if (m_data.Length < byteLen)
Array.Resize<byte>(ref m_data, byteLen + c_overAllocateAmount);
return;
}
/// <summary>
/// Ensures the buffer can hold this number of bits
/// </summary>
internal void InternalEnsureBufferSize(int numberOfBits)
{
int byteLen = ((numberOfBits + 7) >> 3);
if (m_data == null)
{
m_data = new byte[byteLen];
return;
}
if (m_data.Length < byteLen)
Array.Resize<byte>(ref m_data, byteLen);
return;
}
/// <summary>
/// Writes a boolean value using 1 bit
/// </summary>
public void Write(bool value)
{
EnsureBufferSize(m_bitLength + 1);
NetBitWriter.WriteByte((value ? (byte)1 : (byte)0), 1, m_data, m_bitLength);
m_bitLength += 1;
}
/// <summary>
/// Write a byte
/// </summary>
public void Write(byte source)
{
EnsureBufferSize(m_bitLength + 8);
NetBitWriter.WriteByte(source, 8, m_data, m_bitLength);
m_bitLength += 8;
}
/// <summary>
/// Writes a signed byte
/// </summary>
[CLSCompliant(false)]
public void Write(sbyte source)
{
EnsureBufferSize(m_bitLength + 8);
NetBitWriter.WriteByte((byte)source, 8, m_data, m_bitLength);
m_bitLength += 8;
}
/// <summary>
/// Writes 1 to 8 bits of a byte
/// </summary>
public void Write(byte source, int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 8), "Write(byte, numberOfBits) can only write between 1 and 8 bits");
EnsureBufferSize(m_bitLength + numberOfBits);
NetBitWriter.WriteByte(source, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
/// <summary>
/// Writes all bytes in an array
/// </summary>
public void Write(byte[] source)
{
if (source == null)
throw new ArgumentNullException("source");
int bits = source.Length * 8;
EnsureBufferSize(m_bitLength + bits);
NetBitWriter.WriteBytes(source, 0, source.Length, m_data, m_bitLength);
m_bitLength += bits;
}
/// <summary>
/// Writes the specified number of bytes from an array
/// </summary>
public void Write(byte[] source, int offsetInBytes, int numberOfBytes)
{
if (source == null)
throw new ArgumentNullException("source");
int bits = numberOfBytes * 8;
EnsureBufferSize(m_bitLength + bits);
NetBitWriter.WriteBytes(source, offsetInBytes, numberOfBytes, m_data, m_bitLength);
m_bitLength += bits;
}
/// <summary>
/// Writes an unsigned 16 bit integer
/// </summary>
/// <param name="source"></param>
[CLSCompliant(false)]
public void Write(UInt16 source)
{
EnsureBufferSize(m_bitLength + 16);
NetBitWriter.WriteUInt16(source, 16, m_data, m_bitLength);
m_bitLength += 16;
}
/// <summary>
/// Writes an unsigned integer using 1 to 16 bits
/// </summary>
[CLSCompliant(false)]
public void Write(UInt16 source, int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 16), "Write(ushort, numberOfBits) can only write between 1 and 16 bits");
EnsureBufferSize(m_bitLength + numberOfBits);
NetBitWriter.WriteUInt16(source, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
/// <summary>
/// Writes a signed 16 bit integer
/// </summary>
public void Write(Int16 source)
{
EnsureBufferSize(m_bitLength + 16);
NetBitWriter.WriteUInt16((ushort)source, 16, m_data, m_bitLength);
m_bitLength += 16;
}
#if UNSAFE
/// <summary>
/// Writes a 32 bit signed integer
/// </summary>
public unsafe void Write(Int32 source)
{
EnsureBufferSize(m_bitLength + 32);
// can write fast?
if (m_bitLength % 8 == 0)
{
fixed (byte* numRef = &Data[m_bitLength / 8])
{
*((int*)numRef) = source;
}
}
else
{
NetBitWriter.WriteUInt32((UInt32)source, 32, Data, m_bitLength);
}
m_bitLength += 32;
}
#else
/// <summary>
/// Writes a 32 bit signed integer
/// </summary>
public void Write(Int32 source)
{
EnsureBufferSize(m_bitLength + 32);
NetBitWriter.WriteUInt32((UInt32)source, 32, m_data, m_bitLength);
m_bitLength += 32;
}
#endif
#if UNSAFE
/// <summary>
/// Writes a 32 bit unsigned integer
/// </summary>
public unsafe void Write(UInt32 source)
{
EnsureBufferSize(m_bitLength + 32);
// can write fast?
if (m_bitLength % 8 == 0)
{
fixed (byte* numRef = &Data[m_bitLength / 8])
{
*((uint*)numRef) = source;
}
}
else
{
NetBitWriter.WriteUInt32(source, 32, Data, m_bitLength);
}
m_bitLength += 32;
}
#else
/// <summary>
/// Writes a 32 bit unsigned integer
/// </summary>
[CLSCompliant(false)]
public void Write(UInt32 source)
{
EnsureBufferSize(m_bitLength + 32);
NetBitWriter.WriteUInt32(source, 32, m_data, m_bitLength);
m_bitLength += 32;
}
#endif
/// <summary>
/// Writes a 32 bit signed integer
/// </summary>
[CLSCompliant(false)]
public void Write(UInt32 source, int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 32), "Write(uint, numberOfBits) can only write between 1 and 32 bits");
EnsureBufferSize(m_bitLength + numberOfBits);
NetBitWriter.WriteUInt32(source, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
/// <summary>
/// Writes a signed integer using 1 to 32 bits
/// </summary>
public void Write(Int32 source, int numberOfBits)
{
NetException.Assert((numberOfBits > 0 && numberOfBits <= 32), "Write(int, numberOfBits) can only write between 1 and 32 bits");
EnsureBufferSize(m_bitLength + numberOfBits);
if (numberOfBits != 32)
{
// make first bit sign
int signBit = 1 << (numberOfBits - 1);
if (source < 0)
source = (-source - 1) | signBit;
else
source &= (~signBit);
}
NetBitWriter.WriteUInt32((uint)source, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
/// <summary>
/// Writes a 64 bit unsigned integer
/// </summary>
[CLSCompliant(false)]
public void Write(UInt64 source)
{
EnsureBufferSize(m_bitLength + 64);
NetBitWriter.WriteUInt64(source, 64, m_data, m_bitLength);
m_bitLength += 64;
}
/// <summary>
/// Writes an unsigned integer using 1 to 64 bits
/// </summary>
[CLSCompliant(false)]
public void Write(UInt64 source, int numberOfBits)
{
EnsureBufferSize(m_bitLength + numberOfBits);
NetBitWriter.WriteUInt64(source, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
/// <summary>
/// Writes a 64 bit signed integer
/// </summary>
public void Write(Int64 source)
{
EnsureBufferSize(m_bitLength + 64);
ulong usource = (ulong)source;
NetBitWriter.WriteUInt64(usource, 64, m_data, m_bitLength);
m_bitLength += 64;
}
/// <summary>
/// Writes a signed integer using 1 to 64 bits
/// </summary>
public void Write(Int64 source, int numberOfBits)
{
EnsureBufferSize(m_bitLength + numberOfBits);
ulong usource = (ulong)source;
NetBitWriter.WriteUInt64(usource, numberOfBits, m_data, m_bitLength);
m_bitLength += numberOfBits;
}
//
// Floating point
//
#if UNSAFE
/// <summary>
/// Writes a 32 bit floating point value
/// </summary>
public unsafe void Write(float source)
{
uint val = *((uint*)&source);
#if BIGENDIAN
val = NetUtility.SwapByteOrder(val);
#endif
Write(val);
}
#else
/// <summary>
/// Writes a 32 bit floating point value
/// </summary>
public void Write(float source)
{
// Use union to avoid BitConverter.GetBytes() which allocates memory on the heap
SingleUIntUnion su;
su.UIntValue = 0; // must initialize every member of the union to avoid warning
su.SingleValue = source;
#if BIGENDIAN
// swap byte order
su.UIntValue = NetUtility.SwapByteOrder(su.UIntValue);
#endif
Write(su.UIntValue);
}
#endif
#if UNSAFE
/// <summary>
/// Writes a 64 bit floating point value
/// </summary>
public unsafe void Write(double source)
{
ulong val = *((ulong*)&source);
#if BIGENDIAN
val = NetUtility.SwapByteOrder(val);
#endif
Write(val);
}
#else
/// <summary>
/// Writes a 64 bit floating point value
/// </summary>
public void Write(double source)
{
byte[] val = BitConverter.GetBytes(source);
#if BIGENDIAN
// 0 1 2 3 4 5 6 7
// swap byte order
byte tmp = val[7];
val[7] = val[0];
val[0] = tmp;
tmp = val[6];
val[6] = val[1];
val[1] = tmp;
tmp = val[5];
val[5] = val[2];
val[2] = tmp;
tmp = val[4];
val[4] = val[3];
val[3] = tmp;
#endif
Write(val);
}
#endif
//
// Variable bits
//
/// <summary>
/// Write Base128 encoded variable sized unsigned integer of up to 32 bits
/// </summary>
/// <returns>number of bytes written</returns>
[CLSCompliant(false)]
public int WriteVariableUInt32(uint value)
{
int retval = 1;
uint num1 = (uint)value;
while (num1 >= 0x80)
{
this.Write((byte)(num1 | 0x80));
num1 = num1 >> 7;
retval++;
}
this.Write((byte)num1);
return retval;
}
/// <summary>
/// Write Base128 encoded variable sized signed integer of up to 32 bits
/// </summary>
/// <returns>number of bytes written</returns>
public int WriteVariableInt32(int value)
{
uint zigzag = (uint)(value << 1) ^ (uint)(value >> 31);
return WriteVariableUInt32(zigzag);
}
/// <summary>
/// Write Base128 encoded variable sized signed integer of up to 64 bits
/// </summary>
/// <returns>number of bytes written</returns>
public int WriteVariableInt64(Int64 value)
{
ulong zigzag = (ulong)(value << 1) ^ (ulong)(value >> 63);
return WriteVariableUInt64(zigzag);
}
/// <summary>
/// Write Base128 encoded variable sized unsigned integer of up to 64 bits
/// </summary>
/// <returns>number of bytes written</returns>
[CLSCompliant(false)]
public int WriteVariableUInt64(UInt64 value)
{
int retval = 1;
UInt64 num1 = (UInt64)value;
while (num1 >= 0x80)
{
this.Write((byte)(num1 | 0x80));
num1 = num1 >> 7;
retval++;
}
this.Write((byte)num1);
return retval;
}
/// <summary>
/// Compress (lossy) a float in the range -1..1 using numberOfBits bits
/// </summary>
public void WriteSignedSingle(float value, int numberOfBits)
{
NetException.Assert(((value >= -1.0) && (value <= 1.0)), " WriteSignedSingle() must be passed a float in the range -1 to 1; val is " + value);
float unit = (value + 1.0f) * 0.5f;
int maxVal = (1 << numberOfBits) - 1;
uint writeVal = (uint)(unit * (float)maxVal);
Write(writeVal, numberOfBits);
}
/// <summary>
/// Compress (lossy) a float in the range 0..1 using numberOfBits bits
/// </summary>
public void WriteUnitSingle(float value, int numberOfBits)
{
NetException.Assert(((value >= 0.0) && (value <= 1.0)), " WriteUnitSingle() must be passed a float in the range 0 to 1; val is " + value);
int maxValue = (1 << numberOfBits) - 1;
uint writeVal = (uint)(value * (float)maxValue);
Write(writeVal, numberOfBits);
}
/// <summary>
/// Compress a float within a specified range using a certain number of bits
/// </summary>
public void WriteRangedSingle(float value, float min, float max, int numberOfBits)
{
NetException.Assert(((value >= min) && (value <= max)), " WriteRangedSingle() must be passed a float in the range MIN to MAX; val is " + value);
float range = max - min;
float unit = ((value - min) / range);
int maxVal = (1 << numberOfBits) - 1;
Write((UInt32)((float)maxVal * unit), numberOfBits);
}
/// <summary>
/// Writes an integer with the least amount of bits need for the specified range
/// Returns number of bits written
/// </summary>
public int WriteRangedInteger(int min, int max, int value)
{
NetException.Assert(value >= min && value <= max, "Value not within min/max range!");
uint range = (uint)(max - min);
int numBits = NetUtility.BitsToHoldUInt(range);
uint rvalue = (uint)(value - min);
Write(rvalue, numBits);
return numBits;
}
/// <summary>
/// Write a string
/// </summary>
public void Write(string source)
{
if (string.IsNullOrEmpty(source))
{
EnsureBufferSize(m_bitLength + 8);
WriteVariableUInt32(0);
return;
}
byte[] bytes = Encoding.UTF8.GetBytes(source);
EnsureBufferSize(m_bitLength + 8 + (bytes.Length * 8));
WriteVariableUInt32((uint)bytes.Length);
Write(bytes);
}
/// <summary>
/// Writes an endpoint description
/// </summary>
public void Write(IPEndPoint endPoint)
{
byte[] bytes = endPoint.Address.GetAddressBytes();
Write((byte)bytes.Length);
Write(bytes);
Write((ushort)endPoint.Port);
}
/// <summary>
/// Writes the current local time to a message; readable (and convertable to local time) by the remote host using ReadTime()
/// </summary>
public void WriteTime(bool highPrecision)
{
double localTime = NetTime.Now;
if (highPrecision)
Write(localTime);
else
Write((float)localTime);
}
/// <summary>
/// Writes a local timestamp to a message; readable (and convertable to local time) by the remote host using ReadTime()
/// </summary>
public void WriteTime(double localTime, bool highPrecision)
{
if (highPrecision)
Write(localTime);
else
Write((float)localTime);
}
/// <summary>
/// Pads data with enough bits to reach a full byte. Decreases cpu usage for subsequent byte writes.
/// </summary>
public void WritePadBits()
{
m_bitLength = ((m_bitLength + 7) >> 3) * 8;
EnsureBufferSize(m_bitLength);
}
/// <summary>
/// Pads data with the specified number of bits.
/// </summary>
public void WritePadBits(int numberOfBits)
{
m_bitLength += numberOfBits;
EnsureBufferSize(m_bitLength);
}
/// <summary>
/// Append all the bits of message to this message
/// </summary>
public void Write(NetOutgoingMessage message)
{
EnsureBufferSize(m_bitLength + (message.LengthBytes * 8));
Write(message.m_data, 0, message.LengthBytes);
// did we write excessive bits?
int bitsInLastByte = (message.m_bitLength % 8);
if (bitsInLastByte != 0)
{
int excessBits = 8 - bitsInLastByte;
m_bitLength -= excessBits;
}
}
/// <summary>
/// Append all the bits of message to this message
/// </summary>
public void Write(NetIncomingMessage message)
{
EnsureBufferSize(m_bitLength + (message.LengthBytes * 8));
Write(message.m_data, 0, message.LengthBytes);
// did we write excessive bits?
int bitsInLastByte = (message.m_bitLength % 8);
if (bitsInLastByte != 0)
{
int excessBits = 8 - bitsInLastByte;
m_bitLength -= excessBits;
}
}
}
}

View File

@@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Lidgren.Network
{
public partial class NetBuffer
{
/// <summary>
/// Number of bytes to overallocate for each message to avoid resizing
/// </summary>
protected const int c_overAllocateAmount = 4;
private static readonly Dictionary<Type, MethodInfo> s_readMethods;
private static readonly Dictionary<Type, MethodInfo> s_writeMethods;
internal byte[] m_data;
internal int m_bitLength;
internal int m_readPosition;
/// <summary>
/// Gets or sets the internal data buffer
/// </summary>
public byte[] Data
{
get { return m_data; }
set { m_data = value; }
}
/// <summary>
/// Gets or sets the length of the used portion of the buffer in bytes
/// </summary>
public int LengthBytes
{
get { return ((m_bitLength + 7) >> 3); }
set
{
m_bitLength = value * 8;
InternalEnsureBufferSize(m_bitLength);
}
}
/// <summary>
/// Gets or sets the length of the used portion of the buffer in bits
/// </summary>
public int LengthBits
{
get { return m_bitLength; }
set
{
m_bitLength = value;
InternalEnsureBufferSize(m_bitLength);
}
}
/// <summary>
/// Gets or sets the read position in the buffer, in bits (not bytes)
/// </summary>
public long Position
{
get { return (long)m_readPosition; }
set { m_readPosition = (int)value; }
}
/// <summary>
/// Gets the position in the buffer in bytes; note that the bits of the first returned byte may already have been read - check the Position property to make sure.
/// </summary>
public int PositionInBytes
{
get { return (int)(m_readPosition / 8); }
}
static NetBuffer()
{
Type[] integralTypes = typeof(Byte).Assembly.GetTypes();
s_readMethods = new Dictionary<Type, MethodInfo>();
MethodInfo[] methods = typeof(NetIncomingMessage).GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (MethodInfo mi in methods)
{
if (mi.GetParameters().Length == 0 && mi.Name.StartsWith("Read", StringComparison.InvariantCulture) && mi.Name.Substring(4) == mi.ReturnType.Name)
{
s_readMethods[mi.ReturnType] = mi;
}
}
s_writeMethods = new Dictionary<Type, MethodInfo>();
methods = typeof(NetOutgoingMessage).GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (MethodInfo mi in methods)
{
if (mi.Name.Equals("Write", StringComparison.InvariantCulture))
{
ParameterInfo[] pis = mi.GetParameters();
if (pis.Length == 1)
s_writeMethods[pis[0].ParameterType] = mi;
}
}
}
}
}

View File

@@ -1,171 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Net;
namespace Lidgren.Network
{
/// <summary>
/// Specialized version of NetPeer used for a "client" connection. It does not accept any incoming connections and maintains a ServerConnection property
/// </summary>
public class NetClient : NetPeer
{
/// <summary>
/// Gets the connection to the server, if any
/// </summary>
public NetConnection ServerConnection
{
get
{
NetConnection retval = null;
if (m_connections.Count > 0)
{
try
{
retval = m_connections[0];
}
catch
{
// preempted!
return null;
}
}
return retval;
}
}
/// <summary>
/// Gets the connection status of the server connection (or NetConnectionStatus.Disconnected if no connection)
/// </summary>
public NetConnectionStatus ConnectionStatus
{
get
{
var conn = ServerConnection;
if (conn == null)
return NetConnectionStatus.Disconnected;
return conn.Status;
}
}
/// <summary>
/// NetClient constructor
/// </summary>
/// <param name="config"></param>
public NetClient(NetPeerConfiguration config)
: base(config)
{
config.AcceptIncomingConnections = false;
}
/// <summary>
/// Connect to a remote server
/// </summary>
/// <param name="remoteEndPoint">The remote endpoint to connect to</param>
/// <param name="hailMessage">The hail message to pass</param>
/// <returns>server connection, or null if already connected</returns>
public override NetConnection Connect(IPEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
{
lock (m_connections)
{
if (m_connections.Count > 0)
{
LogWarning("Connect attempt failed; Already connected");
return null;
}
}
lock (m_handshakes)
{
if (m_handshakes.Count > 0)
{
LogWarning("Connect attempt failed; Handshake already in progress");
return null;
}
}
return base.Connect(remoteEndPoint, hailMessage);
}
/// <summary>
/// Disconnect from server
/// </summary>
/// <param name="byeMessage">reason for disconnect</param>
public void Disconnect(string byeMessage)
{
NetConnection serverConnection = ServerConnection;
if (serverConnection == null)
{
lock (m_handshakes)
{
if (m_handshakes.Count > 0)
{
LogVerbose("Aborting connection attempt");
foreach(var hs in m_handshakes)
hs.Value.Disconnect(byeMessage);
return;
}
}
LogWarning("Disconnect requested when not connected!");
return;
}
serverConnection.Disconnect(byeMessage);
}
/// <summary>
/// Sends message to server
/// </summary>
public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method)
{
NetConnection serverConnection = ServerConnection;
if (serverConnection == null)
{
LogWarning("Cannot send message, no server connection!");
return NetSendResult.FailedNotConnected;
}
return serverConnection.SendMessage(msg, method, 0);
}
/// <summary>
/// Sends message to server
/// </summary>
public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
{
NetConnection serverConnection = ServerConnection;
if (serverConnection == null)
{
LogWarning("Cannot send message, no server connection!");
return NetSendResult.FailedNotConnected;
}
return serverConnection.SendMessage(msg, method, sequenceChannel);
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
return "[NetClient " + ServerConnection + "]";
}
}
}

View File

@@ -1,477 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Lidgren.Network
{
public partial class NetConnection
{
internal bool m_connectRequested;
internal bool m_disconnectRequested;
internal bool m_connectionInitiator;
internal string m_disconnectMessage;
internal NetIncomingMessage m_remoteHailMessage;
internal float m_lastHandshakeSendTime;
internal int m_handshakeAttempts;
/// <summary>
/// The message that the remote part specified via Connect() or Approve() - can be null.
/// </summary>
public NetIncomingMessage RemoteHailMessage { get { return m_remoteHailMessage; } }
// heartbeat called when connection still is in m_handshakes of NetPeer
internal void UnconnectedHeartbeat(float now)
{
m_peer.VerifyNetworkThread();
if (m_disconnectRequested)
ExecuteDisconnect(m_disconnectMessage, true);
if (m_connectRequested)
{
switch (m_status)
{
case NetConnectionStatus.Connected:
case NetConnectionStatus.RespondedConnect:
// reconnect
ExecuteDisconnect("Reconnecting", true);
break;
case NetConnectionStatus.InitiatedConnect:
// send another connect attempt
SendConnect(now);
break;
case NetConnectionStatus.Disconnected:
throw new NetException("This connection is Disconnected; spent. A new one should have been created");
case NetConnectionStatus.Disconnecting:
// let disconnect finish first
break;
case NetConnectionStatus.None:
default:
SendConnect(now);
break;
}
return;
}
if (now - m_lastHandshakeSendTime > m_peerConfiguration.m_resendHandshakeInterval)
{
if (m_handshakeAttempts >= m_peerConfiguration.m_maximumHandshakeAttempts)
{
// failed to connect
ExecuteDisconnect("Failed to establish connection - no response from remote host", true);
return;
}
// resend handshake
switch (m_status)
{
case NetConnectionStatus.InitiatedConnect:
SendConnect(now);
break;
case NetConnectionStatus.RespondedConnect:
SendConnectResponse(now, true);
break;
case NetConnectionStatus.None:
case NetConnectionStatus.ReceivedInitiation:
m_peer.LogWarning("Time to resend handshake, but status is " + m_status);
break;
case NetConnectionStatus.RespondedAwaitingApproval:
// awaiting approval
m_lastHandshakeSendTime = now; // postpone handshake resend
break;
default:
m_peer.LogWarning("Time to resend handshake, but status is " + m_status);
break;
}
}
}
internal void ExecuteDisconnect(string reason, bool sendByeMessage)
{
m_peer.VerifyNetworkThread();
// clear send queues
for (int i = 0; i < m_sendChannels.Length; i++)
{
NetSenderChannelBase channel = m_sendChannels[i];
if (channel != null)
channel.Reset();
}
if (sendByeMessage)
SendDisconnect(reason, true);
SetStatus(NetConnectionStatus.Disconnected, reason);
// in case we're still in handshake
lock (m_peer.m_handshakes)
m_peer.m_handshakes.Remove(m_remoteEndPoint);
m_disconnectRequested = false;
m_connectRequested = false;
m_handshakeAttempts = 0;
}
internal void SendConnect(float now)
{
m_peer.VerifyNetworkThread();
int preAllocate = 13 + m_peerConfiguration.AppIdentifier.Length;
preAllocate += (m_localHailMessage == null ? 0 : m_localHailMessage.LengthBytes);
NetOutgoingMessage om = m_peer.CreateMessage(preAllocate);
om.m_messageType = NetMessageType.Connect;
om.Write(m_peerConfiguration.AppIdentifier);
om.Write(m_peer.m_uniqueIdentifier);
om.Write(now);
WriteLocalHail(om);
m_peer.SendLibrary(om, m_remoteEndPoint);
m_connectRequested = false;
m_lastHandshakeSendTime = now;
m_handshakeAttempts++;
if (m_handshakeAttempts > 1)
m_peer.LogDebug("Resending Connect...");
SetStatus(NetConnectionStatus.InitiatedConnect, "Locally requested connect");
}
internal void SendConnectResponse(float now, bool onLibraryThread)
{
if (onLibraryThread)
m_peer.VerifyNetworkThread();
NetOutgoingMessage om = m_peer.CreateMessage(m_peerConfiguration.AppIdentifier.Length + 13 + (m_localHailMessage == null ? 0 : m_localHailMessage.LengthBytes));
om.m_messageType = NetMessageType.ConnectResponse;
om.Write(m_peerConfiguration.AppIdentifier);
om.Write(m_peer.m_uniqueIdentifier);
om.Write(now);
WriteLocalHail(om);
if (onLibraryThread)
m_peer.SendLibrary(om, m_remoteEndPoint);
else
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<System.Net.IPEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
m_lastHandshakeSendTime = now;
m_handshakeAttempts++;
if (m_handshakeAttempts > 1)
m_peer.LogDebug("Resending ConnectResponse...");
SetStatus(NetConnectionStatus.RespondedConnect, "Remotely requested connect");
}
internal void SendDisconnect(string reason, bool onLibraryThread)
{
if (onLibraryThread)
m_peer.VerifyNetworkThread();
NetOutgoingMessage om = m_peer.CreateMessage(reason);
om.m_messageType = NetMessageType.Disconnect;
if (onLibraryThread)
m_peer.SendLibrary(om, m_remoteEndPoint);
else
m_peer.m_unsentUnconnectedMessages.Enqueue(new NetTuple<System.Net.IPEndPoint, NetOutgoingMessage>(m_remoteEndPoint, om));
}
private void WriteLocalHail(NetOutgoingMessage om)
{
if (m_localHailMessage != null)
{
byte[] hi = m_localHailMessage.Data;
if (hi != null && hi.Length >= m_localHailMessage.LengthBytes)
{
if (om.LengthBytes + m_localHailMessage.LengthBytes > m_peerConfiguration.m_maximumTransmissionUnit - 10)
throw new NetException("Hail message too large; can maximally be " + (m_peerConfiguration.m_maximumTransmissionUnit - 10 - om.LengthBytes));
om.Write(m_localHailMessage.Data, 0, m_localHailMessage.LengthBytes);
}
}
}
internal void SendConnectionEstablished()
{
NetOutgoingMessage om = m_peer.CreateMessage(4);
om.m_messageType = NetMessageType.ConnectionEstablished;
om.Write((float)NetTime.Now);
m_peer.SendLibrary(om, m_remoteEndPoint);
m_handshakeAttempts = 0;
InitializePing();
if (m_status != NetConnectionStatus.Connected)
SetStatus(NetConnectionStatus.Connected, "Connected to " + NetUtility.ToHexString(m_remoteUniqueIdentifier));
}
/// <summary>
/// Approves this connection; sending a connection response to the remote host
/// </summary>
public void Approve()
{
if (m_status != NetConnectionStatus.RespondedAwaitingApproval)
{
m_peer.LogWarning("Approve() called in wrong status; expected RespondedAwaitingApproval; got " + m_status);
return;
}
m_localHailMessage = null;
m_handshakeAttempts = 0;
SendConnectResponse((float)NetTime.Now, false);
}
/// <summary>
/// Approves this connection; sending a connection response to the remote host
/// </summary>
/// <param name="localHail">The local hail message that will be set as RemoteHailMessage on the remote host</param>
public void Approve(NetOutgoingMessage localHail)
{
if (m_status != NetConnectionStatus.RespondedAwaitingApproval)
{
m_peer.LogWarning("Approve() called in wrong status; expected RespondedAwaitingApproval; got " + m_status);
return;
}
m_localHailMessage = localHail;
m_handshakeAttempts = 0;
SendConnectResponse((float)NetTime.Now, false);
}
/// <summary>
/// Denies this connection; disconnecting it
/// </summary>
public void Deny()
{
Deny(string.Empty);
}
/// <summary>
/// Denies this connection; disconnecting it
/// </summary>
/// <param name="reason">The stated reason for the disconnect, readable as a string in the StatusChanged message on the remote host</param>
public void Deny(string reason)
{
// send disconnect; remove from handshakes
SendDisconnect(reason, false);
// remove from handshakes
m_peer.m_handshakes.Remove(m_remoteEndPoint); // TODO: make this more thread safe? we're on user thread
}
internal void ReceivedHandshake(double now, NetMessageType tp, int ptr, int payloadLength)
{
m_peer.VerifyNetworkThread();
byte[] hail;
switch (tp)
{
case NetMessageType.Connect:
if (m_status == NetConnectionStatus.ReceivedInitiation)
{
// Whee! Server full has already been checked
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
if (ok)
{
if (hail != null)
{
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
m_remoteHailMessage.LengthBits = (hail.Length * 8);
}
else
{
m_remoteHailMessage = null;
}
if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionApproval))
{
// ok, let's not add connection just yet
NetIncomingMessage appMsg = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionApproval, (m_remoteHailMessage == null ? 0 : m_remoteHailMessage.LengthBytes));
appMsg.m_receiveTime = now;
appMsg.m_senderConnection = this;
appMsg.m_senderEndPoint = this.m_remoteEndPoint;
if (m_remoteHailMessage != null)
appMsg.Write(m_remoteHailMessage.m_data, 0, m_remoteHailMessage.LengthBytes);
SetStatus(NetConnectionStatus.RespondedAwaitingApproval, "Awaiting approval");
m_peer.ReleaseMessage(appMsg);
return;
}
SendConnectResponse((float)now, true);
}
return;
}
if (m_status == NetConnectionStatus.RespondedAwaitingApproval)
{
m_peer.LogWarning("Ignoring multiple Connect() most likely due to a delayed Approval");
return;
}
if (m_status == NetConnectionStatus.RespondedConnect)
{
// our ConnectResponse must have been lost
SendConnectResponse((float)now, true);
return;
}
m_peer.LogDebug("Unhandled Connect: " + tp + ", status is " + m_status + " length: " + payloadLength);
break;
case NetMessageType.ConnectResponse:
switch (m_status)
{
case NetConnectionStatus.InitiatedConnect:
// awesome
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
if (ok)
{
if (hail != null)
{
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
m_remoteHailMessage.LengthBits = (hail.Length * 8);
}
else
{
m_remoteHailMessage = null;
}
m_peer.AcceptConnection(this);
SendConnectionEstablished();
return;
}
break;
case NetConnectionStatus.RespondedConnect:
// hello, wtf?
break;
case NetConnectionStatus.Disconnecting:
case NetConnectionStatus.Disconnected:
case NetConnectionStatus.ReceivedInitiation:
case NetConnectionStatus.None:
// wtf? anyway, bye!
break;
case NetConnectionStatus.Connected:
// my ConnectionEstablished must have been lost, send another one
SendConnectionEstablished();
return;
}
break;
case NetMessageType.ConnectionEstablished:
switch (m_status)
{
case NetConnectionStatus.Connected:
// ok...
break;
case NetConnectionStatus.Disconnected:
case NetConnectionStatus.Disconnecting:
case NetConnectionStatus.None:
// too bad, almost made it
break;
case NetConnectionStatus.ReceivedInitiation:
// uh, a little premature... ignore
break;
case NetConnectionStatus.InitiatedConnect:
// weird, should have been RespondedConnect...
break;
case NetConnectionStatus.RespondedConnect:
// awesome
NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
InitializeRemoteTimeOffset(msg.ReadSingle());
m_peer.AcceptConnection(this);
InitializePing();
SetStatus(NetConnectionStatus.Connected, "Connected to " + NetUtility.ToHexString(m_remoteUniqueIdentifier));
return;
}
break;
case NetMessageType.Disconnect:
// ouch
string reason = "Ouch";
try
{
NetIncomingMessage inc = m_peer.SetupReadHelperMessage(ptr, payloadLength);
reason = inc.ReadString();
}
catch
{
}
ExecuteDisconnect(reason, false);
break;
case NetMessageType.Discovery:
m_peer.HandleIncomingDiscoveryRequest(now, m_remoteEndPoint, ptr, payloadLength);
return;
case NetMessageType.DiscoveryResponse:
m_peer.HandleIncomingDiscoveryResponse(now, m_remoteEndPoint, ptr, payloadLength);
return;
case NetMessageType.Ping:
// silently ignore
return;
default:
m_peer.LogDebug("Unhandled type during handshake: " + tp + " length: " + payloadLength);
break;
}
}
private bool ValidateHandshakeData(int ptr, int payloadLength, out byte[] hail)
{
hail = null;
// create temporary incoming message
NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
try
{
string remoteAppIdentifier = msg.ReadString();
long remoteUniqueIdentifier = msg.ReadInt64();
InitializeRemoteTimeOffset(msg.ReadSingle());
int remainingBytes = payloadLength - (msg.PositionInBytes - ptr);
if (remainingBytes > 0)
hail = msg.ReadBytes(remainingBytes);
if (remoteAppIdentifier != m_peer.m_configuration.AppIdentifier)
{
// wrong app identifier
ExecuteDisconnect("Wrong application identifier!", true);
return false;
}
m_remoteUniqueIdentifier = remoteUniqueIdentifier;
}
catch(Exception ex)
{
// whatever; we failed
ExecuteDisconnect("Handshake data validation failed", true);
m_peer.LogWarning("ReadRemoteHandshakeData failed: " + ex.Message);
return false;
}
return true;
}
/// <summary>
/// Disconnect from the remote peer
/// </summary>
/// <param name="byeMessage">the message to send with the disconnect message</param>
public void Disconnect(string byeMessage)
{
// user or library thread
if (m_status == NetConnectionStatus.None || m_status == NetConnectionStatus.Disconnected)
return;
m_peer.LogVerbose("Disconnect requested for " + this);
m_disconnectMessage = byeMessage;
if (m_status != NetConnectionStatus.Disconnected && m_status != NetConnectionStatus.None)
SetStatus(NetConnectionStatus.Disconnecting, byeMessage);
m_handshakeAttempts = 0;
m_disconnectRequested = true;
}
}
}

View File

@@ -1,145 +0,0 @@
using System;
namespace Lidgren.Network
{
public partial class NetConnection
{
private float m_sentPingTime;
private int m_sentPingNumber;
private float m_averageRoundtripTime;
private float m_timeoutDeadline = float.MaxValue;
// local time value + m_remoteTimeOffset = remote time value
internal double m_remoteTimeOffset;
/// <summary>
/// Gets the current average roundtrip time in seconds
/// </summary>
public float AverageRoundtripTime { get { return m_averageRoundtripTime; } }
/// <summary>
/// Time offset between this peer and the remote peer
/// </summary>
public float RemoteTimeOffset { get { return (float)m_remoteTimeOffset; } }
// this might happen more than once
internal void InitializeRemoteTimeOffset(float remoteSendTime)
{
m_remoteTimeOffset = (remoteSendTime + (m_averageRoundtripTime / 2.0)) - NetTime.Now;
}
/// <summary>
/// Gets local time value comparable to NetTime.Now from a remote value
/// </summary>
public double GetLocalTime(double remoteTimestamp)
{
return remoteTimestamp - m_remoteTimeOffset;
}
/// <summary>
/// Gets the remote time value for a local time value produced by NetTime.Now
/// </summary>
public double GetRemoteTime(double localTimestamp)
{
return localTimestamp + m_remoteTimeOffset;
}
internal void InitializePing()
{
float now = (float)NetTime.Now;
// randomize ping sent time (0.25 - 1.0 x ping interval)
m_sentPingTime = now;
m_sentPingTime -= (m_peerConfiguration.PingInterval * 0.25f); // delay ping for a little while
m_sentPingTime -= (NetRandom.Instance.NextSingle() * (m_peerConfiguration.PingInterval * 0.75f));
m_timeoutDeadline = now + (m_peerConfiguration.m_connectionTimeout * 2.0f); // initially allow a little more time
// make it better, quick :-)
SendPing();
}
internal void SendPing()
{
m_peer.VerifyNetworkThread();
m_sentPingNumber++;
m_sentPingTime = (float)NetTime.Now;
NetOutgoingMessage om = m_peer.CreateMessage(1);
om.Write((byte)m_sentPingNumber); // truncating to 0-255
om.m_messageType = NetMessageType.Ping;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
bool connectionReset;
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
m_statistics.PacketSent(len, 1);
}
internal void SendPong(int pingNumber)
{
m_peer.VerifyNetworkThread();
NetOutgoingMessage om = m_peer.CreateMessage(5);
om.Write((byte)pingNumber);
om.Write((float)NetTime.Now); // we should update this value to reflect the exact point in time the packet is SENT
om.m_messageType = NetMessageType.Pong;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
bool connectionReset;
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
m_statistics.PacketSent(len, 1);
}
internal void ReceivedPong(float now, int pongNumber, float remoteSendTime)
{
if ((byte)pongNumber != (byte)m_sentPingNumber)
{
m_peer.LogVerbose("Ping/Pong mismatch; dropped message?");
return;
}
m_timeoutDeadline = now + m_peerConfiguration.m_connectionTimeout;
float rtt = now - m_sentPingTime;
NetException.Assert(rtt >= 0);
double diff = (remoteSendTime + (rtt / 2.0)) - now;
if (m_averageRoundtripTime < 0)
{
m_remoteTimeOffset = diff;
m_averageRoundtripTime = rtt;
m_peer.LogDebug("Initiated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + " Remote time is: " + (now + diff));
}
else
{
m_averageRoundtripTime = (m_averageRoundtripTime * 0.7f) + (float)(rtt * 0.3f);
m_remoteTimeOffset = ((m_remoteTimeOffset * (double)(m_sentPingNumber - 1)) + diff) / (double)m_sentPingNumber;
m_peer.LogVerbose("Updated average roundtrip time to " + NetTime.ToReadable(m_averageRoundtripTime) + ", remote time to " + (now + m_remoteTimeOffset) + " (ie. diff " + m_remoteTimeOffset + ")");
}
// update resend delay for all channels
float resendDelay = GetResendDelay();
foreach (var chan in m_sendChannels)
{
var rchan = chan as NetReliableSenderChannel;
if (rchan != null)
rchan.m_resendDelay = resendDelay;
}
// notify the application that average rtt changed
if (m_peer.m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ConnectionLatencyUpdated))
{
NetIncomingMessage update = m_peer.CreateIncomingMessage(NetIncomingMessageType.ConnectionLatencyUpdated, 4);
update.m_senderConnection = this;
update.m_senderEndPoint = this.m_remoteEndPoint;
update.Write(rtt);
m_peer.ReleaseMessage(update);
}
}
}
}

View File

@@ -1,166 +0,0 @@
using System;
namespace Lidgren.Network
{
public partial class NetConnection
{
private enum ExpandMTUStatus
{
None,
InProgress,
Finished
}
private const int c_protocolMaxMTU = (int)((((float)ushort.MaxValue / 8.0f) - 1.0f));
private ExpandMTUStatus m_expandMTUStatus;
private int m_largestSuccessfulMTU;
private int m_smallestFailedMTU;
private int m_lastSentMTUAttemptSize;
private double m_lastSentMTUAttemptTime;
private int m_mtuAttemptFails;
internal int m_currentMTU;
internal void InitExpandMTU(double now)
{
m_lastSentMTUAttemptTime = now + m_peerConfiguration.m_expandMTUFrequency + 1.5f + m_averageRoundtripTime; // wait a tiny bit before starting to expand mtu
m_largestSuccessfulMTU = 512;
m_smallestFailedMTU = -1;
m_currentMTU = m_peerConfiguration.MaximumTransmissionUnit;
}
private void MTUExpansionHeartbeat(double now)
{
if (m_expandMTUStatus == ExpandMTUStatus.Finished)
return;
if (m_expandMTUStatus == ExpandMTUStatus.None)
{
if (m_peerConfiguration.m_autoExpandMTU == false)
{
FinalizeMTU(m_currentMTU);
return;
}
// begin expansion
ExpandMTU(now, true);
return;
}
if (now > m_lastSentMTUAttemptTime + m_peerConfiguration.ExpandMTUFrequency)
{
m_mtuAttemptFails++;
if (m_mtuAttemptFails == 3)
{
FinalizeMTU(m_currentMTU);
return;
}
// timed out; ie. failed
m_smallestFailedMTU = m_lastSentMTUAttemptSize;
ExpandMTU(now, false);
}
}
private void ExpandMTU(double now, bool succeeded)
{
int tryMTU;
// we've nevered encountered failure
if (m_smallestFailedMTU == -1)
{
// we've never encountered failure; expand by 25% each time
tryMTU = (int)((float)m_currentMTU * 1.25f);
}
else
{
// we HAVE encountered failure; so try in between
tryMTU = (int)(((float)m_smallestFailedMTU + (float)m_largestSuccessfulMTU) / 2.0f);
}
if (tryMTU > c_protocolMaxMTU)
tryMTU = c_protocolMaxMTU;
if (tryMTU == m_largestSuccessfulMTU)
{
FinalizeMTU(m_largestSuccessfulMTU);
return;
}
SendExpandMTU(now, tryMTU);
}
private void SendExpandMTU(double now, int size)
{
NetOutgoingMessage om = m_peer.CreateMessage(size);
byte[] tmp = new byte[size];
om.Write(tmp);
om.m_messageType = NetMessageType.ExpandMTURequest;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
bool ok = m_peer.SendMTUPacket(len, m_remoteEndPoint);
if (ok == false)
{
// failure
if (m_smallestFailedMTU == -1 || size < m_smallestFailedMTU)
{
m_smallestFailedMTU = size;
m_mtuAttemptFails++;
if (m_mtuAttemptFails >= m_peerConfiguration.ExpandMTUFailAttempts)
{
FinalizeMTU(m_largestSuccessfulMTU);
return;
}
}
ExpandMTU(now, false);
return;
}
m_lastSentMTUAttemptSize = size;
m_lastSentMTUAttemptTime = now;
m_statistics.PacketSent(len, 1);
}
private void FinalizeMTU(int size)
{
if (m_expandMTUStatus == ExpandMTUStatus.Finished)
return;
m_expandMTUStatus = ExpandMTUStatus.Finished;
m_currentMTU = size;
if (m_currentMTU != m_peerConfiguration.m_maximumTransmissionUnit)
m_peer.LogDebug("Expanded Maximum Transmission Unit to: " + m_currentMTU + " bytes");
return;
}
private void SendMTUSuccess(int size)
{
NetOutgoingMessage om = m_peer.CreateMessage(4);
om.Write(size);
om.m_messageType = NetMessageType.ExpandMTUSuccess;
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
bool connectionReset;
m_peer.SendPacket(len, m_remoteEndPoint, 1, out connectionReset);
m_statistics.PacketSent(len, 1);
}
private void HandleExpandMTUSuccess(double now, int size)
{
if (size > m_largestSuccessfulMTU)
m_largestSuccessfulMTU = size;
if (size < m_currentMTU)
{
return;
}
m_currentMTU = size;
ExpandMTU(now, true);
}
}
}

View File

@@ -1,502 +0,0 @@
using System;
using System.Net;
using System.Threading;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Represents a connection to a remote peer
/// </summary>
[DebuggerDisplay("RemoteUniqueIdentifier={RemoteUniqueIdentifier} RemoteEndPoint={remoteEndPoint}")]
public partial class NetConnection
{
internal NetPeer m_peer;
internal NetPeerConfiguration m_peerConfiguration;
internal NetConnectionStatus m_status;
internal NetConnectionStatus m_visibleStatus;
internal IPEndPoint m_remoteEndPoint;
internal NetSenderChannelBase[] m_sendChannels;
internal NetReceiverChannelBase[] m_receiveChannels;
internal NetOutgoingMessage m_localHailMessage;
internal long m_remoteUniqueIdentifier;
internal NetQueue<NetTuple<NetMessageType, int>> m_queuedOutgoingAcks;
internal NetQueue<NetTuple<NetMessageType, int>> m_queuedIncomingAcks;
private int m_sendBufferWritePtr;
private int m_sendBufferNumMessages;
private object m_tag;
internal NetConnectionStatistics m_statistics;
/// <summary>
/// Gets or sets the application defined object containing data about the connection
/// </summary>
public object Tag
{
get { return m_tag; }
set { m_tag = value; }
}
/// <summary>
/// Gets the peer which holds this connection
/// </summary>
public NetPeer Peer { get { return m_peer; } }
/// <summary>
/// Gets the current status of the connection (synced to the last status message read)
/// </summary>
public NetConnectionStatus Status { get { return m_visibleStatus; } }
/// <summary>
/// Gets various statistics for this connection
/// </summary>
public NetConnectionStatistics Statistics { get { return m_statistics; } }
/// <summary>
/// Gets the remote endpoint for the connection
/// </summary>
public IPEndPoint RemoteEndPoint { get { return m_remoteEndPoint; } }
/// <summary>
/// Gets the unique identifier of the remote NetPeer for this connection
/// </summary>
public long RemoteUniqueIdentifier { get { return m_remoteUniqueIdentifier; } }
/// <summary>
/// Gets the local hail message that was sent as part of the handshake
/// </summary>
public NetOutgoingMessage LocalHailMessage { get { return m_localHailMessage; } }
// gets the time before automatically resending an unacked message
internal float GetResendDelay()
{
float avgRtt = m_averageRoundtripTime;
if (avgRtt <= 0)
avgRtt = 0.1f; // "default" resend is based on 100 ms roundtrip time
return 0.02f + (avgRtt * 2.0f); // 20 ms + double rtt
}
internal NetConnection(NetPeer peer, IPEndPoint remoteEndPoint)
{
m_peer = peer;
m_peerConfiguration = m_peer.Configuration;
m_status = NetConnectionStatus.None;
m_visibleStatus = NetConnectionStatus.None;
m_remoteEndPoint = remoteEndPoint;
m_sendChannels = new NetSenderChannelBase[NetConstants.NumTotalChannels];
m_receiveChannels = new NetReceiverChannelBase[NetConstants.NumTotalChannels];
m_queuedOutgoingAcks = new NetQueue<NetTuple<NetMessageType, int>>(4);
m_queuedIncomingAcks = new NetQueue<NetTuple<NetMessageType, int>>(4);
m_statistics = new NetConnectionStatistics(this);
m_averageRoundtripTime = -1.0f;
m_currentMTU = m_peerConfiguration.MaximumTransmissionUnit;
}
/// <summary>
/// Change the internal endpoint to this new one. Used when, during handshake, a switch in port is detected (due to NAT)
/// </summary>
internal void MutateEndPoint(IPEndPoint endPoint)
{
m_remoteEndPoint = endPoint;
}
internal void SetStatus(NetConnectionStatus status, string reason)
{
// user or library thread
if (status == m_status)
return;
m_status = status;
if (reason == null)
reason = string.Empty;
if (m_status == NetConnectionStatus.Connected)
{
m_timeoutDeadline = (float)NetTime.Now + m_peerConfiguration.m_connectionTimeout;
m_peer.LogVerbose("Timeout deadline initialized to " + m_timeoutDeadline);
}
if (m_peerConfiguration.IsMessageTypeEnabled(NetIncomingMessageType.StatusChanged))
{
NetIncomingMessage info = m_peer.CreateIncomingMessage(NetIncomingMessageType.StatusChanged, 4 + reason.Length + (reason.Length > 126 ? 2 : 1));
info.m_senderConnection = this;
info.m_senderEndPoint = m_remoteEndPoint;
info.Write((byte)m_status);
info.Write(reason);
m_peer.ReleaseMessage(info);
}
else
{
// app dont want those messages, update visible status immediately
m_visibleStatus = m_status;
}
}
internal void Heartbeat(float now, uint frameCounter)
{
m_peer.VerifyNetworkThread();
NetException.Assert(m_status != NetConnectionStatus.InitiatedConnect && m_status != NetConnectionStatus.RespondedConnect);
if ((frameCounter % 5) == 0)
{
if (now > m_timeoutDeadline)
{
//
// connection timed out
//
m_peer.LogVerbose("Connection timed out at " + now + " deadline was " + m_timeoutDeadline);
ExecuteDisconnect("Connection timed out", true);
}
// send ping?
if (m_status == NetConnectionStatus.Connected)
{
if (now > m_sentPingTime + m_peer.m_configuration.m_pingInterval)
SendPing();
// handle expand mtu
MTUExpansionHeartbeat(now);
}
if (m_disconnectRequested)
{
ExecuteDisconnect(m_disconnectMessage, true);
return;
}
}
bool connectionReset; // TODO: handle connection reset
//
// Note: at this point m_sendBufferWritePtr and m_sendBufferNumMessages may be non-null; resends may already be queued up
//
byte[] sendBuffer = m_peer.m_sendBuffer;
int mtu = m_currentMTU;
if ((frameCounter % 3) == 0) // coalesce a few frames
{
//
// send ack messages
//
while (m_queuedOutgoingAcks.Count > 0)
{
int acks = (mtu - (m_sendBufferWritePtr + 5)) / 3; // 3 bytes per actual ack
if (acks > m_queuedOutgoingAcks.Count)
acks = m_queuedOutgoingAcks.Count;
NetException.Assert(acks > 0);
m_sendBufferNumMessages++;
// write acks header
sendBuffer[m_sendBufferWritePtr++] = (byte)NetMessageType.Acknowledge;
sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number
sendBuffer[m_sendBufferWritePtr++] = 0; // no sequence number
int len = (acks * 3) * 8; // bits
sendBuffer[m_sendBufferWritePtr++] = (byte)len;
sendBuffer[m_sendBufferWritePtr++] = (byte)(len >> 8);
// write acks
for (int i = 0; i < acks; i++)
{
NetTuple<NetMessageType, int> tuple;
m_queuedOutgoingAcks.TryDequeue(out tuple);
sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item1;
sendBuffer[m_sendBufferWritePtr++] = (byte)tuple.Item2;
sendBuffer[m_sendBufferWritePtr++] = (byte)(tuple.Item2 >> 8);
}
if (m_queuedOutgoingAcks.Count > 0)
{
// send packet and go for another round of acks
NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0);
m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset);
m_statistics.PacketSent(m_sendBufferWritePtr, 1);
m_sendBufferWritePtr = 0;
m_sendBufferNumMessages = 0;
}
}
//
// Parse incoming acks (may trigger resends)
//
NetTuple<NetMessageType, int> incAck;
while (m_queuedIncomingAcks.TryDequeue(out incAck))
{
NetSenderChannelBase chan = m_sendChannels[(int)incAck.Item1 - 1];
if (chan == null)
chan = CreateSenderChannel(incAck.Item1);
chan.ReceiveAcknowledge(now, incAck.Item2);
}
}
//
// send queued messages
//
if (m_peer.m_executeFlushSendQueue)
{
for (int i = m_sendChannels.Length - 1; i >= 0; i--) // Reverse order so reliable messages are sent first
{
var channel = m_sendChannels[i];
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
if (channel != null)
channel.SendQueuedMessages(now);
NetException.Assert(m_sendBufferWritePtr < 1 || m_sendBufferNumMessages > 0);
}
}
//
// Put on wire data has been written to send buffer but not yet sent
//
if (m_sendBufferWritePtr > 0)
{
m_peer.VerifyNetworkThread();
NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0);
m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connectionReset);
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
m_sendBufferWritePtr = 0;
m_sendBufferNumMessages = 0;
}
}
// Queue an item for immediate sending on the wire
// This method is called from the ISenderChannels
internal void QueueSendMessage(NetOutgoingMessage om, int seqNr)
{
m_peer.VerifyNetworkThread();
int sz = om.GetEncodedSize();
if (sz > m_currentMTU)
m_peer.LogWarning("Message larger than MTU! Fragmentation must have failed!");
if (m_sendBufferWritePtr + sz > m_currentMTU)
{
bool connReset; // TODO: handle connection reset
NetException.Assert(m_sendBufferWritePtr > 0 && m_sendBufferNumMessages > 0); // or else the message should have been fragmented earlier
m_peer.SendPacket(m_sendBufferWritePtr, m_remoteEndPoint, m_sendBufferNumMessages, out connReset);
m_statistics.PacketSent(m_sendBufferWritePtr, m_sendBufferNumMessages);
m_sendBufferWritePtr = 0;
m_sendBufferNumMessages = 0;
}
m_sendBufferWritePtr = om.Encode(m_peer.m_sendBuffer, m_sendBufferWritePtr, seqNr);
m_sendBufferNumMessages++;
NetException.Assert(m_sendBufferWritePtr > 0, "Encoded zero size message?");
NetException.Assert(m_sendBufferNumMessages > 0);
}
/// <summary>
/// Send a message to this remote connection
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="method">How to deliver the message</param>
/// <param name="sequenceChannel">Sequence channel within the delivery method</param>
public NetSendResult SendMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
{
return m_peer.SendMessage(msg, this, method, sequenceChannel);
}
// called by SendMessage() and NetPeer.SendMessage; ie. may be user thread
internal NetSendResult EnqueueMessage(NetOutgoingMessage msg, NetDeliveryMethod method, int sequenceChannel)
{
if (m_status != NetConnectionStatus.Connected)
return NetSendResult.FailedNotConnected;
NetMessageType tp = (NetMessageType)((int)method + sequenceChannel);
msg.m_messageType = tp;
// TODO: do we need to make this more thread safe?
int channelSlot = (int)method - 1 + sequenceChannel;
NetSenderChannelBase chan = m_sendChannels[channelSlot];
if (chan == null)
chan = CreateSenderChannel(tp);
if (msg.GetEncodedSize() > m_currentMTU)
throw new NetException("Message too large! Fragmentation failure?");
var retval = chan.Enqueue(msg);
if (retval == NetSendResult.Sent && m_peerConfiguration.m_autoFlushSendQueue == false)
retval = NetSendResult.Queued; // queued since we're not autoflushing
return retval;
}
// may be on user thread
private NetSenderChannelBase CreateSenderChannel(NetMessageType tp)
{
NetSenderChannelBase chan;
lock (m_sendChannels)
{
NetDeliveryMethod method = NetUtility.GetDeliveryMethod(tp);
int sequenceChannel = (int)tp - (int)method;
int channelSlot = (int)method - 1 + sequenceChannel;
if (m_sendChannels[channelSlot] != null)
{
// we were pre-empted by another call to this method
chan = m_sendChannels[channelSlot];
}
else
{
switch (method)
{
case NetDeliveryMethod.Unreliable:
case NetDeliveryMethod.UnreliableSequenced:
chan = new NetUnreliableSenderChannel(this, NetUtility.GetWindowSize(method));
break;
case NetDeliveryMethod.ReliableOrdered:
chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
break;
case NetDeliveryMethod.ReliableSequenced:
case NetDeliveryMethod.ReliableUnordered:
default:
chan = new NetReliableSenderChannel(this, NetUtility.GetWindowSize(method));
break;
}
m_sendChannels[channelSlot] = chan;
}
}
return chan;
}
// received a library message while Connected
internal void ReceivedLibraryMessage(NetMessageType tp, int ptr, int payloadLength)
{
m_peer.VerifyNetworkThread();
float now = (float)NetTime.Now;
switch (tp)
{
case NetMessageType.Disconnect:
NetIncomingMessage msg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
ExecuteDisconnect(msg.ReadString(), false);
break;
case NetMessageType.Acknowledge:
for (int i = 0; i < payloadLength; i+=3)
{
NetMessageType acktp = (NetMessageType)m_peer.m_receiveBuffer[ptr++]; // netmessagetype
int seqNr = m_peer.m_receiveBuffer[ptr++];
seqNr |= (m_peer.m_receiveBuffer[ptr++] << 8);
// need to enqueue this and handle it in the netconnection heartbeat; so be able to send resends together with normal sends
m_queuedIncomingAcks.Enqueue(new NetTuple<NetMessageType, int>(acktp, seqNr));
}
break;
case NetMessageType.Ping:
int pingNr = m_peer.m_receiveBuffer[ptr++];
SendPong(pingNr);
break;
case NetMessageType.Pong:
NetIncomingMessage pmsg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
int pongNr = pmsg.ReadByte();
float remoteSendTime = pmsg.ReadSingle();
ReceivedPong(now, pongNr, remoteSendTime);
break;
case NetMessageType.ExpandMTURequest:
SendMTUSuccess(payloadLength);
break;
case NetMessageType.ExpandMTUSuccess:
NetIncomingMessage emsg = m_peer.SetupReadHelperMessage(ptr, payloadLength);
int size = emsg.ReadInt32();
HandleExpandMTUSuccess(now, size);
break;
default:
m_peer.LogWarning("Connection received unhandled library message: " + tp);
break;
}
}
internal void ReceivedMessage(NetIncomingMessage msg)
{
m_peer.VerifyNetworkThread();
NetMessageType tp = msg.m_receivedMessageType;
int channelSlot = (int)tp - 1;
NetReceiverChannelBase chan = m_receiveChannels[channelSlot];
if (chan == null)
chan = CreateReceiverChannel(tp);
chan.ReceiveMessage(msg);
}
private NetReceiverChannelBase CreateReceiverChannel(NetMessageType tp)
{
m_peer.VerifyNetworkThread();
// create receiver channel
NetReceiverChannelBase chan;
NetDeliveryMethod method = NetUtility.GetDeliveryMethod(tp);
switch (method)
{
case NetDeliveryMethod.Unreliable:
chan = new NetUnreliableUnorderedReceiver(this);
break;
case NetDeliveryMethod.ReliableOrdered:
chan = new NetReliableOrderedReceiver(this, NetConstants.ReliableOrderedWindowSize);
break;
case NetDeliveryMethod.UnreliableSequenced:
chan = new NetUnreliableSequencedReceiver(this);
break;
case NetDeliveryMethod.ReliableUnordered:
chan = new NetReliableUnorderedReceiver(this, NetConstants.ReliableOrderedWindowSize);
break;
case NetDeliveryMethod.ReliableSequenced:
chan = new NetReliableSequencedReceiver(this, NetConstants.ReliableSequencedWindowSize);
break;
default:
throw new NetException("Unhandled NetDeliveryMethod!");
}
int channelSlot = (int)tp - 1;
NetException.Assert(m_receiveChannels[channelSlot] == null);
m_receiveChannels[channelSlot] = chan;
return chan;
}
internal void QueueAck(NetMessageType tp, int sequenceNumber)
{
m_queuedOutgoingAcks.Enqueue(new NetTuple<NetMessageType, int>(tp, sequenceNumber));
}
/// <summary>
/// Zero windowSize indicates that the channel is not yet instantiated (used)
/// Negative freeWindowSlots means this amount of messages are currently queued but delayed due to closed window
/// </summary>
public void GetSendQueueInfo(NetDeliveryMethod method, int sequenceChannel, out int windowSize, out int freeWindowSlots)
{
int channelSlot = (int)method - 1 + sequenceChannel;
var chan = m_sendChannels[channelSlot];
if (chan == null)
{
windowSize = NetUtility.GetWindowSize(method);
freeWindowSlots = windowSize;
return;
}
windowSize = chan.WindowSize;
freeWindowSlots = chan.GetAllowedSends() - chan.m_queuedSends.Count;
return;
}
internal void Shutdown(string reason)
{
ExecuteDisconnect(reason, true);
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
return "[NetConnection to " + m_remoteEndPoint + "]";
}
}
}

View File

@@ -1,201 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Uncomment the line below to get statistics in RELEASE builds
#define USE_RELEASE_STATISTICS
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace Lidgren.Network
{
internal enum MessageResendReason
{
Delay,
HoleInSequence
}
/// <summary>
/// Statistics for a NetConnection instance
/// </summary>
public sealed class NetConnectionStatistics
{
private readonly NetConnection m_connection;
internal int m_sentPackets;
internal int m_receivedPackets;
internal int m_sentMessages;
internal int m_receivedMessages;
internal int m_sentBytes;
internal int m_receivedBytes;
internal int m_resentMessagesDueToDelay;
internal int m_resentMessagesDueToHole;
internal NetConnectionStatistics(NetConnection conn)
{
m_connection = conn;
Reset();
}
internal void Reset()
{
m_sentPackets = 0;
m_receivedPackets = 0;
m_sentBytes = 0;
m_receivedBytes = 0;
}
/// <summary>
/// Gets the number of sent packets for this connection
/// </summary>
public int SentPackets { get { return m_sentPackets; } }
/// <summary>
/// Gets the number of received packets for this connection
/// </summary>
public int ReceivedPackets { get { return m_receivedPackets; } }
/// <summary>
/// Gets the number of sent bytes for this connection
/// </summary>
public int SentBytes { get { return m_sentBytes; } }
/// <summary>
/// Gets the number of received bytes for this connection
/// </summary>
public int ReceivedBytes { get { return m_receivedBytes; } }
/// <summary>
/// Gets the number of resent reliable messages for this connection
/// </summary>
public int ResentMessages { get { return m_resentMessagesDueToHole + m_resentMessagesDueToDelay; } }
#if USE_RELEASE_STATISTICS
internal void PacketSent(int numBytes, int numMessages)
{
NetException.Assert(numBytes > 0 && numMessages > 0);
m_sentPackets++;
m_sentBytes += numBytes;
m_sentMessages += numMessages;
}
#else
[Conditional("DEBUG")]
internal void PacketSent(int numBytes, int numMessages)
{
NetException.Assert(numBytes > 0 && numMessages > 0);
m_sentPackets++;
m_sentBytes += numBytes;
m_sentMessages += numMessages;
}
#endif
#if USE_RELEASE_STATISTICS
internal void PacketReceived(int numBytes, int numMessages)
{
NetException.Assert(numBytes > 0 && numMessages > 0);
m_receivedPackets++;
m_receivedBytes += numBytes;
m_receivedMessages += numMessages;
}
#else
[Conditional("DEBUG")]
internal void PacketReceived(int numBytes, int numMessages)
{
NetException.Assert(numBytes > 0 && numMessages > 0);
m_receivedPackets++;
m_receivedBytes += numBytes;
m_receivedMessages += numMessages;
}
#endif
#if USE_RELEASE_STATISTICS
internal void MessageResent(MessageResendReason reason)
{
if (reason == MessageResendReason.Delay)
m_resentMessagesDueToDelay++;
else
m_resentMessagesDueToHole++;
}
#else
[Conditional("DEBUG")]
internal void MessageResent(MessageResendReason reason)
{
if (reason == MessageResendReason.Delay)
m_resentMessagesDueToDelay++;
else
m_resentMessagesDueToHole++;
}
#endif
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
StringBuilder bdr = new StringBuilder();
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
if (m_resentMessagesDueToDelay > 0)
bdr.AppendLine("Resent messages (delay): " + m_resentMessagesDueToDelay);
if (m_resentMessagesDueToDelay > 0)
bdr.AppendLine("Resent messages (holes): " + m_resentMessagesDueToHole);
int numUnsent = 0;
int numStored = 0;
foreach (NetSenderChannelBase sendChan in m_connection.m_sendChannels)
{
if (sendChan == null)
continue;
numUnsent += sendChan.m_queuedSends.Count;
var relSendChan = sendChan as NetReliableSenderChannel;
if (relSendChan != null)
{
for (int i = 0; i < relSendChan.m_storedMessages.Length; i++)
if (relSendChan.m_storedMessages[i].Message != null)
numStored++;
}
}
int numWithheld = 0;
foreach (NetReceiverChannelBase recChan in m_connection.m_receiveChannels)
{
var relRecChan = recChan as NetReliableOrderedReceiver;
if (relRecChan != null)
{
for (int i = 0; i < relRecChan.m_withheldMessages.Length; i++)
if (relRecChan.m_withheldMessages[i] != null)
numWithheld++;
}
}
bdr.AppendLine("Unsent messages: " + numUnsent);
bdr.AppendLine("Stored messages: " + numStored);
bdr.AppendLine("Withheld messages: " + numWithheld);
return bdr.ToString();
}
}
}

View File

@@ -1,68 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace Lidgren.Network
{
/// <summary>
/// Status for a NetConnection instance
/// </summary>
public enum NetConnectionStatus
{
/// <summary>
/// No connection, or attempt, in place
/// </summary>
None,
/// <summary>
/// Connect has been sent; waiting for ConnectResponse
/// </summary>
InitiatedConnect,
/// <summary>
/// Connect was received, but ConnectResponse hasn't been sent yet
/// </summary>
ReceivedInitiation,
/// <summary>
/// Connect was received and ApprovalMessage released to the application; awaiting Approve() or Deny()
/// </summary>
RespondedAwaitingApproval, // We got Connect, released ApprovalMessage
/// <summary>
/// Connect was received and ConnectResponse has been sent; waiting for ConnectionEstablished
/// </summary>
RespondedConnect, // we got Connect, sent ConnectResponse
/// <summary>
/// Connected
/// </summary>
Connected, // we received ConnectResponse (if initiator) or ConnectionEstablished (if passive)
/// <summary>
/// In the process of disconnecting
/// </summary>
Disconnecting,
/// <summary>
/// Disconnected
/// </summary>
Disconnected
}
}

View File

@@ -1,57 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace Lidgren.Network
{
/// <summary>
/// All the constants used when compiling the library
/// </summary>
internal static class NetConstants
{
internal const int NumTotalChannels = 99;
internal const int NetChannelsPerDeliveryMethod = 32;
internal const int NumSequenceNumbers = 1024;
internal const int HeaderByteSize = 5;
internal const int UnreliableWindowSize = 128;
internal const int ReliableOrderedWindowSize = 64;
internal const int ReliableSequencedWindowSize = 64;
internal const int DefaultWindowSize = 64;
internal const int MaxFragmentationGroups = ushort.MaxValue - 1;
internal const int UnfragmentedMessageHeaderSize = 5;
/// <summary>
/// Number of channels which needs a sequence number to work
/// </summary>
internal const int NumSequencedChannels = ((int)NetMessageType.UserReliableOrdered1 + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserSequenced1;
/// <summary>
/// Number of reliable channels
/// </summary>
internal const int NumReliableChannels = ((int)NetMessageType.UserReliableOrdered1 + NetConstants.NetChannelsPerDeliveryMethod) - (int)NetMessageType.UserReliableUnordered;
internal const string ConnResetMessage = "Connection was reset by remote host";
}
}

View File

@@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Lidgren.Network
{
/// <summary>
/// How the library deals with resends and handling of late messages
/// </summary>
public enum NetDeliveryMethod : byte
{
//
// Actually a publicly visible subset of NetMessageType
//
/// <summary>
/// Indicates an error
/// </summary>
Unknown = 0,
/// <summary>
/// Unreliable, unordered delivery
/// </summary>
Unreliable = 1,
/// <summary>
/// Unreliable delivery, but automatically dropping late messages
/// </summary>
UnreliableSequenced = 2,
/// <summary>
/// Reliable delivery, but unordered
/// </summary>
ReliableUnordered = 34,
/// <summary>
/// Reliable delivery, except for late messages which are dropped
/// </summary>
ReliableSequenced = 35,
/// <summary>
/// Reliable, ordered delivery
/// </summary>
ReliableOrdered = 67,
}
}

View File

@@ -1,83 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.Runtime.Serialization;
namespace Lidgren.Network
{
/// <summary>
/// Exception thrown in the Lidgren Network Library
/// </summary>
[Serializable]
public sealed class NetException : Exception
{
/// <summary>
/// NetException constructor
/// </summary>
public NetException()
: base()
{
}
/// <summary>
/// NetException constructor
/// </summary>
public NetException(string message)
: base(message)
{
}
/// <summary>
/// NetException constructor
/// </summary>
public NetException(string message, Exception inner)
: base(message, inner)
{
}
/// <summary>
/// NetException constructor
/// </summary>
private NetException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
/// <summary>
/// Throws an exception, in DEBUG only, if first parameter is false
/// </summary>
[Conditional("DEBUG")]
public static void Assert(bool isOk, string message)
{
if (!isOk)
throw new NetException(message);
}
/// <summary>
/// Throws an exception, in DEBUG only, if first parameter is false
/// </summary>
[Conditional("DEBUG")]
public static void Assert(bool isOk)
{
if (!isOk)
throw new NetException();
}
}
}

View File

@@ -1,174 +0,0 @@
using System;
namespace Lidgren.Network
{
internal static class NetFragmentationHelper
{
internal static int WriteHeader(
byte[] destination,
int ptr,
int group,
int totalBits,
int chunkByteSize,
int chunkNumber)
{
uint num1 = (uint)group;
while (num1 >= 0x80)
{
destination[ptr++] = (byte)(num1 | 0x80);
num1 = num1 >> 7;
}
destination[ptr++] = (byte)num1;
// write variable length fragment total bits
uint num2 = (uint)totalBits;
while (num2 >= 0x80)
{
destination[ptr++] = (byte)(num2 | 0x80);
num2 = num2 >> 7;
}
destination[ptr++] = (byte)num2;
// write variable length fragment chunk size
uint num3 = (uint)chunkByteSize;
while (num3 >= 0x80)
{
destination[ptr++] = (byte)(num3 | 0x80);
num3 = num3 >> 7;
}
destination[ptr++] = (byte)num3;
// write variable length fragment chunk number
uint num4 = (uint)chunkNumber;
while (num4 >= 0x80)
{
destination[ptr++] = (byte)(num4 | 0x80);
num4 = num4 >> 7;
}
destination[ptr++] = (byte)num4;
return ptr;
}
internal static int ReadHeader(byte[] buffer, int ptr, out int group, out int totalBits, out int chunkByteSize, out int chunkNumber)
{
int num1 = 0;
int num2 = 0;
while (true)
{
byte num3 = buffer[ptr++];
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
num2 += 7;
if ((num3 & 0x80) == 0)
{
group = num1;
break;
}
}
num1 = 0;
num2 = 0;
while (true)
{
byte num3 = buffer[ptr++];
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
num2 += 7;
if ((num3 & 0x80) == 0)
{
totalBits = num1;
break;
}
}
num1 = 0;
num2 = 0;
while (true)
{
byte num3 = buffer[ptr++];
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
num2 += 7;
if ((num3 & 0x80) == 0)
{
chunkByteSize = num1;
break;
}
}
num1 = 0;
num2 = 0;
while (true)
{
byte num3 = buffer[ptr++];
num1 |= (num3 & 0x7f) << (num2 & 0x1f);
num2 += 7;
if ((num3 & 0x80) == 0)
{
chunkNumber = num1;
break;
}
}
return ptr;
}
internal static int GetFragmentationHeaderSize(int groupId, int totalBytes, int chunkByteSize, int numChunks)
{
int len = 4;
// write variable length fragment group id
uint num1 = (uint)groupId;
while (num1 >= 0x80)
{
len++;
num1 = num1 >> 7;
}
// write variable length fragment total bits
uint num2 = (uint)(totalBytes * 8);
while (num2 >= 0x80)
{
len++;
num2 = num2 >> 7;
}
// write variable length fragment chunk byte size
uint num3 = (uint)chunkByteSize;
while (num3 >= 0x80)
{
len++;
num3 = num3 >> 7;
}
// write variable length fragment chunk number
uint num4 = (uint)numChunks;
while (num4 >= 0x80)
{
len++;
num4 = num4 >> 7;
}
return len;
}
internal static int GetBestChunkSize(int group, int totalBytes, int mtu)
{
int tryNumChunks = (totalBytes / (mtu - 8)) + 1;
int tryChunkSize = (totalBytes / tryNumChunks) + 1; // +1 since we immediately decrement it in the loop
int headerSize = 0;
do
{
tryChunkSize--; // keep reducing chunk size until it fits within MTU including header
int numChunks = totalBytes / tryChunkSize;
if (numChunks * tryChunkSize < totalBytes)
numChunks++;
headerSize = GetFragmentationHeaderSize(group, totalBytes, tryChunkSize, numChunks);
} while (tryChunkSize + headerSize + 5 + 1 >= mtu);
return tryChunkSize;
}
}
}

View File

@@ -1,12 +0,0 @@
using System;
namespace Lidgren.Network
{
public sealed class NetFragmentationInfo
{
public int TotalFragmentCount;
public bool[] Received;
public int TotalReceived;
public int FragmentSize;
}
}

View File

@@ -1,115 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Net;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Incoming message either sent from a remote peer or generated within the library
/// </summary>
[DebuggerDisplay("Type={MessageType} LengthBits={LengthBits}")]
public sealed class NetIncomingMessage : NetBuffer
{
internal NetIncomingMessageType m_incomingMessageType;
internal IPEndPoint m_senderEndPoint;
internal NetConnection m_senderConnection;
internal int m_sequenceNumber;
internal NetMessageType m_receivedMessageType;
internal bool m_isFragment;
internal double m_receiveTime;
/// <summary>
/// Gets the type of this incoming message
/// </summary>
public NetIncomingMessageType MessageType { get { return m_incomingMessageType; } }
/// <summary>
/// Gets the delivery method this message was sent with (if user data)
/// </summary>
public NetDeliveryMethod DeliveryMethod { get { return NetUtility.GetDeliveryMethod(m_receivedMessageType); } }
/// <summary>
/// Gets the sequence channel this message was sent with (if user data)
/// </summary>
public int SequenceChannel { get { return (int)m_receivedMessageType - (int)NetUtility.GetDeliveryMethod(m_receivedMessageType); } }
/// <summary>
/// IPEndPoint of sender, if any
/// </summary>
public IPEndPoint SenderEndPoint { get { return m_senderEndPoint; } }
/// <summary>
/// NetConnection of sender, if any
/// </summary>
public NetConnection SenderConnection { get { return m_senderConnection; } }
/// <summary>
/// What local time the message was received from the network
/// </summary>
public double ReceiveTime { get { return m_receiveTime; } }
internal NetIncomingMessage()
{
}
internal NetIncomingMessage(NetIncomingMessageType tp)
{
m_incomingMessageType = tp;
}
internal void Reset()
{
m_incomingMessageType = NetIncomingMessageType.Error;
m_readPosition = 0;
m_receivedMessageType = NetMessageType.LibraryError;
m_senderConnection = null;
m_bitLength = 0;
m_isFragment = false;
}
/// <summary>
/// Decrypt a message
/// </summary>
/// <param name="encryption">The encryption algorithm used to encrypt the message</param>
/// <returns>true on success</returns>
public bool Decrypt(INetEncryption encryption)
{
return encryption.Decrypt(this);
}
/// <summary>
/// Reads a value, in local time comparable to NetTime.Now, written using WriteTime()
/// Must have a connected sender
/// </summary>
public double ReadTime(bool highPrecision)
{
return ReadTime(m_senderConnection, highPrecision);
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
return "[NetIncomingMessage #" + m_sequenceNumber + " " + this.LengthBytes + " bytes]";
}
}
}

View File

@@ -1,105 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics.CodeAnalysis;
namespace Lidgren.Network
{
/// <summary>
/// The type of a NetIncomingMessage
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1027:MarkEnumsWithFlags")]
public enum NetIncomingMessageType
{
//
// library note: values are power-of-two, but they are not flags - it's a convenience for NetPeerConfiguration.DisabledMessageTypes
//
/// <summary>
/// Error; this value should never appear
/// </summary>
Error = 0,
/// <summary>
/// Status for a connection changed
/// </summary>
StatusChanged = 1 << 0, // Data (string)
/// <summary>
/// Data sent using SendUnconnectedMessage
/// </summary>
UnconnectedData = 1 << 1, // Data Based on data received
/// <summary>
/// Connection approval is needed
/// </summary>
ConnectionApproval = 1 << 2, // Data
/// <summary>
/// Application data
/// </summary>
Data = 1 << 3, // Data Based on data received
/// <summary>
/// Receipt of delivery
/// </summary>
Receipt = 1 << 4, // Data
/// <summary>
/// Discovery request for a response
/// </summary>
DiscoveryRequest = 1 << 5, // (no data)
/// <summary>
/// Discovery response to a request
/// </summary>
DiscoveryResponse = 1 << 6, // Data
/// <summary>
/// Verbose debug message
/// </summary>
VerboseDebugMessage = 1 << 7, // Data (string)
/// <summary>
/// Debug message
/// </summary>
DebugMessage = 1 << 8, // Data (string)
/// <summary>
/// Warning message
/// </summary>
WarningMessage = 1 << 9, // Data (string)
/// <summary>
/// Error message
/// </summary>
ErrorMessage = 1 << 10, // Data (string)
/// <summary>
/// NAT introduction was successful
/// </summary>
NatIntroductionSuccess = 1 << 11, // Data (as passed to master server)
/// <summary>
/// A roundtrip was measured and NetConnection.AverageRoundtripTime was updated
/// </summary>
ConnectionLatencyUpdated = 1 << 12, // Seconds as a Single
}
}

View File

@@ -1,175 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace Lidgren.Network
{
internal enum NetMessageType : byte
{
Unconnected = 0,
UserUnreliable = 1,
UserSequenced1 = 2,
UserSequenced2 = 3,
UserSequenced3 = 4,
UserSequenced4 = 5,
UserSequenced5 = 6,
UserSequenced6 = 7,
UserSequenced7 = 8,
UserSequenced8 = 9,
UserSequenced9 = 10,
UserSequenced10 = 11,
UserSequenced11 = 12,
UserSequenced12 = 13,
UserSequenced13 = 14,
UserSequenced14 = 15,
UserSequenced15 = 16,
UserSequenced16 = 17,
UserSequenced17 = 18,
UserSequenced18 = 19,
UserSequenced19 = 20,
UserSequenced20 = 21,
UserSequenced21 = 22,
UserSequenced22 = 23,
UserSequenced23 = 24,
UserSequenced24 = 25,
UserSequenced25 = 26,
UserSequenced26 = 27,
UserSequenced27 = 28,
UserSequenced28 = 29,
UserSequenced29 = 30,
UserSequenced30 = 31,
UserSequenced31 = 32,
UserSequenced32 = 33,
UserReliableUnordered = 34,
UserReliableSequenced1 = 35,
UserReliableSequenced2 = 36,
UserReliableSequenced3 = 37,
UserReliableSequenced4 = 38,
UserReliableSequenced5 = 39,
UserReliableSequenced6 = 40,
UserReliableSequenced7 = 41,
UserReliableSequenced8 = 42,
UserReliableSequenced9 = 43,
UserReliableSequenced10 = 44,
UserReliableSequenced11 = 45,
UserReliableSequenced12 = 46,
UserReliableSequenced13 = 47,
UserReliableSequenced14 = 48,
UserReliableSequenced15 = 49,
UserReliableSequenced16 = 50,
UserReliableSequenced17 = 51,
UserReliableSequenced18 = 52,
UserReliableSequenced19 = 53,
UserReliableSequenced20 = 54,
UserReliableSequenced21 = 55,
UserReliableSequenced22 = 56,
UserReliableSequenced23 = 57,
UserReliableSequenced24 = 58,
UserReliableSequenced25 = 59,
UserReliableSequenced26 = 60,
UserReliableSequenced27 = 61,
UserReliableSequenced28 = 62,
UserReliableSequenced29 = 63,
UserReliableSequenced30 = 64,
UserReliableSequenced31 = 65,
UserReliableSequenced32 = 66,
UserReliableOrdered1 = 67,
UserReliableOrdered2 = 68,
UserReliableOrdered3 = 69,
UserReliableOrdered4 = 70,
UserReliableOrdered5 = 71,
UserReliableOrdered6 = 72,
UserReliableOrdered7 = 73,
UserReliableOrdered8 = 74,
UserReliableOrdered9 = 75,
UserReliableOrdered10 = 76,
UserReliableOrdered11 = 77,
UserReliableOrdered12 = 78,
UserReliableOrdered13 = 79,
UserReliableOrdered14 = 80,
UserReliableOrdered15 = 81,
UserReliableOrdered16 = 82,
UserReliableOrdered17 = 83,
UserReliableOrdered18 = 84,
UserReliableOrdered19 = 85,
UserReliableOrdered20 = 86,
UserReliableOrdered21 = 87,
UserReliableOrdered22 = 88,
UserReliableOrdered23 = 89,
UserReliableOrdered24 = 90,
UserReliableOrdered25 = 91,
UserReliableOrdered26 = 92,
UserReliableOrdered27 = 93,
UserReliableOrdered28 = 94,
UserReliableOrdered29 = 95,
UserReliableOrdered30 = 96,
UserReliableOrdered31 = 97,
UserReliableOrdered32 = 98,
Unused1 = 99,
Unused2 = 100,
Unused3 = 101,
Unused4 = 102,
Unused5 = 103,
Unused6 = 104,
Unused7 = 105,
Unused8 = 106,
Unused9 = 107,
Unused10 = 108,
Unused11 = 109,
Unused12 = 110,
Unused13 = 111,
Unused14 = 112,
Unused15 = 113,
Unused16 = 114,
Unused17 = 115,
Unused18 = 116,
Unused19 = 117,
Unused20 = 118,
Unused21 = 119,
Unused22 = 120,
Unused23 = 121,
Unused24 = 122,
Unused25 = 123,
Unused26 = 124,
Unused27 = 125,
Unused28 = 126,
Unused29 = 127,
LibraryError = 128,
Ping = 129, // used for RTT calculation
Pong = 130, // used for RTT calculation
Connect = 131,
ConnectResponse = 132,
ConnectionEstablished = 133,
Acknowledge = 134,
Disconnect = 135,
Discovery = 136,
DiscoveryResponse = 137,
NatPunchMessage = 138, // send between peers
NatIntroduction = 139, // send to master server
ExpandMTURequest = 140,
ExpandMTUSuccess = 141,
}
}

View File

@@ -1,110 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net;
namespace Lidgren.Network
{
public partial class NetPeer
{
/// <summary>
/// Send NetIntroduction to hostExternal and clientExternal; introducing client to host
/// </summary>
public void Introduce(
IPEndPoint hostInternal,
IPEndPoint hostExternal,
IPEndPoint clientInternal,
IPEndPoint clientExternal,
string token)
{
// send message to client
NetOutgoingMessage msg = CreateMessage(10 + token.Length + 1);
msg.m_messageType = NetMessageType.NatIntroduction;
msg.Write((byte)0);
msg.Write(hostInternal);
msg.Write(hostExternal);
msg.Write(token);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(clientExternal, msg));
// send message to host
msg = CreateMessage(10 + token.Length + 1);
msg.m_messageType = NetMessageType.NatIntroduction;
msg.Write((byte)1);
msg.Write(clientInternal);
msg.Write(clientExternal);
msg.Write(token);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(hostExternal, msg));
}
/// <summary>
/// Called when host/client receives a NatIntroduction message from a master server
/// </summary>
private void HandleNatIntroduction(int ptr)
{
VerifyNetworkThread();
// read intro
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
byte hostByte = tmp.ReadByte();
IPEndPoint remoteInternal = tmp.ReadIPEndPoint();
IPEndPoint remoteExternal = tmp.ReadIPEndPoint();
string token = tmp.ReadString();
bool isHost = (hostByte != 0);
LogDebug("NAT introduction received; we are designated " + (isHost ? "host" : "client"));
NetOutgoingMessage punch;
if (!isHost && m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.NatIntroductionSuccess) == false)
return; // no need to punch - we're not listening for nat intros!
// send internal punch
punch = CreateMessage(1);
punch.m_messageType = NetMessageType.NatPunchMessage;
punch.Write(hostByte);
punch.Write(token);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(remoteInternal, punch));
// send external punch
punch = CreateMessage(1);
punch.m_messageType = NetMessageType.NatPunchMessage;
punch.Write(hostByte);
punch.Write(token);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(remoteExternal, punch));
}
/// <summary>
/// Called when receiving a NatPunchMessage from a remote endpoint
/// </summary>
private void HandleNatPunch(int ptr, IPEndPoint senderEndPoint)
{
NetIncomingMessage tmp = SetupReadHelperMessage(ptr, 1000); // never mind length
byte fromHostByte = tmp.ReadByte();
if (fromHostByte == 0)
{
// it's from client
LogDebug("NAT punch received from " + senderEndPoint + " we're host, so we ignore this");
return; // don't alert hosts about nat punch successes; only clients
}
string token = tmp.ReadString();
LogDebug("NAT punch received from " + senderEndPoint + " we're client, so we've succeeded - token is " + token);
//
// Release punch success to client; enabling him to Connect() to msg.SenderIPEndPoint if token is ok
//
NetIncomingMessage punchSuccess = CreateIncomingMessage(NetIncomingMessageType.NatIntroductionSuccess, 10);
punchSuccess.m_senderEndPoint = senderEndPoint;
punchSuccess.Write(token);
ReleaseMessage(punchSuccess);
// send a return punch just for good measure
var punch = CreateMessage(1);
punch.m_messageType = NetMessageType.NatPunchMessage;
punch.Write((byte)0);
punch.Write(token);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(senderEndPoint, punch));
}
}
}

View File

@@ -1,132 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Outgoing message used to send data to remote peer(s)
/// </summary>
[DebuggerDisplay("LengthBits={LengthBits}")]
public sealed class NetOutgoingMessage : NetBuffer
{
internal NetMessageType m_messageType;
internal bool m_isSent;
internal int m_recyclingCount;
internal int m_fragmentGroup; // which group of fragments ths belongs to
internal int m_fragmentGroupTotalBits; // total number of bits in this group
internal int m_fragmentChunkByteSize; // size, in bytes, of every chunk but the last one
internal int m_fragmentChunkNumber; // which number chunk this is, starting with 0
internal NetOutgoingMessage()
{
}
internal void Reset()
{
m_messageType = NetMessageType.LibraryError;
m_bitLength = 0;
m_isSent = false;
m_recyclingCount = 0;
m_fragmentGroup = 0;
}
internal int Encode(byte[] intoBuffer, int ptr, int sequenceNumber)
{
// 8 bits - NetMessageType
// 1 bit - Fragment?
// 15 bits - Sequence number
// 16 bits - Payload length in bits
intoBuffer[ptr++] = (byte)m_messageType;
byte low = (byte)((sequenceNumber << 1) | (m_fragmentGroup == 0 ? 0 : 1));
intoBuffer[ptr++] = low;
intoBuffer[ptr++] = (byte)(sequenceNumber >> 7);
if (m_fragmentGroup == 0)
{
intoBuffer[ptr++] = (byte)m_bitLength;
intoBuffer[ptr++] = (byte)(m_bitLength >> 8);
int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
if (byteLen > 0)
{
Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen);
ptr += byteLen;
}
}
else
{
int wasPtr = ptr;
intoBuffer[ptr++] = (byte)m_bitLength;
intoBuffer[ptr++] = (byte)(m_bitLength >> 8);
//
// write fragmentation header
//
ptr = NetFragmentationHelper.WriteHeader(intoBuffer, ptr, m_fragmentGroup, m_fragmentGroupTotalBits, m_fragmentChunkByteSize, m_fragmentChunkNumber);
int hdrLen = ptr - wasPtr - 2;
// update length
int realBitLength = m_bitLength + (hdrLen * 8);
intoBuffer[wasPtr] = (byte)realBitLength;
intoBuffer[wasPtr + 1] = (byte)(realBitLength >> 8);
int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
if (byteLen > 0)
{
Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen);
ptr += byteLen;
}
}
NetException.Assert(ptr > 0);
return ptr;
}
internal int GetEncodedSize()
{
int retval = NetConstants.UnfragmentedMessageHeaderSize; // regular headers
if (m_fragmentGroup != 0)
retval += NetFragmentationHelper.GetFragmentationHeaderSize(m_fragmentGroup, m_fragmentGroupTotalBits / 8, m_fragmentChunkByteSize, m_fragmentChunkNumber);
retval += this.LengthBytes;
return retval;
}
/// <summary>
/// Encrypt this message using the provided algorithm; no more writing can be done before sending it or the message will be corrupt!
/// </summary>
public bool Encrypt(INetEncryption encryption)
{
return encryption.Encrypt(this);
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
return "[NetOutgoingMessage " + m_messageType + " " + this.LengthBytes + " bytes]";
}
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.Net;
namespace Lidgren.Network
{
public partial class NetPeer
{
/// <summary>
/// Emit a discovery signal to all hosts on your subnet
/// </summary>
public void DiscoverLocalPeers(int serverPort)
{
NetOutgoingMessage om = CreateMessage(0);
om.m_messageType = NetMessageType.Discovery;
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(new IPEndPoint(IPAddress.Broadcast, serverPort), om));
}
/// <summary>
/// Emit a discovery signal to a single known host
/// </summary>
public bool DiscoverKnownPeer(string host, int serverPort)
{
IPAddress address = NetUtility.Resolve(host);
if (address == null)
return false;
DiscoverKnownPeer(new IPEndPoint(address, serverPort));
return true;
}
/// <summary>
/// Emit a discovery signal to a single known host
/// </summary>
public void DiscoverKnownPeer(IPEndPoint endPoint)
{
NetOutgoingMessage om = CreateMessage(0);
om.m_messageType = NetMessageType.Discovery;
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(endPoint, om));
}
/// <summary>
/// Send a discovery response message
/// </summary>
public void SendDiscoveryResponse(NetOutgoingMessage msg, IPEndPoint recipient)
{
if (recipient == null)
throw new ArgumentNullException("recipient");
if (msg == null)
msg = CreateMessage(0);
else if (msg.m_isSent)
throw new NetException("Message has already been sent!");
if (msg.LengthBytes >= m_configuration.MaximumTransmissionUnit)
throw new NetException("Cannot send discovery message larger than MTU (currently " + m_configuration.MaximumTransmissionUnit + " bytes)");
msg.m_messageType = NetMessageType.DiscoveryResponse;
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(recipient, msg));
}
}
}

View File

@@ -1,158 +0,0 @@
using System;
using System.Threading;
using System.Collections.Generic;
namespace Lidgren.Network
{
internal class ReceivedFragmentGroup
{
public float LastReceived;
public byte[] Data;
public NetBitVector ReceivedChunks;
}
public partial class NetPeer
{
private int m_lastUsedFragmentGroup;
private Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>> m_receivedFragmentGroups;
// on user thread
private void SendFragmentedMessage(NetOutgoingMessage msg, IList<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
{
// Note: this group id is PER SENDING/NetPeer; ie. same id is sent to all recipients;
// this should be ok however; as long as recipients differentiate between same id but different sender
int group = Interlocked.Increment(ref m_lastUsedFragmentGroup);
if (group >= NetConstants.MaxFragmentationGroups)
{
// @TODO: not thread safe; but in practice probably not an issue
m_lastUsedFragmentGroup = 1;
group = 1;
}
msg.m_fragmentGroup = group;
// do not send msg; but set fragmentgroup in case user tries to recycle it immediately
// create fragmentation specifics
int totalBytes = msg.LengthBytes;
// determine minimum mtu for all recipients
int mtu = GetMTU(recipients);
int bytesPerChunk = NetFragmentationHelper.GetBestChunkSize(group, totalBytes, mtu);
int numChunks = totalBytes / bytesPerChunk;
if (numChunks * bytesPerChunk < totalBytes)
numChunks++;
int bitsPerChunk = bytesPerChunk * 8;
int bitsLeft = msg.LengthBits;
for (int i = 0; i < numChunks; i++)
{
NetOutgoingMessage chunk = CreateMessage(mtu);
chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft);
chunk.m_data = msg.m_data;
chunk.m_fragmentGroup = group;
chunk.m_fragmentGroupTotalBits = totalBytes * 8;
chunk.m_fragmentChunkByteSize = bytesPerChunk;
chunk.m_fragmentChunkNumber = i;
NetException.Assert(chunk.m_bitLength != 0);
NetException.Assert(chunk.GetEncodedSize() < mtu);
Interlocked.Add(ref chunk.m_recyclingCount, recipients.Count);
foreach (NetConnection recipient in recipients)
recipient.EnqueueMessage(chunk, method, sequenceChannel);
bitsLeft -= bitsPerChunk;
}
return;
}
private void HandleReleasedFragment(NetIncomingMessage im)
{
//
// read fragmentation header and combine fragments
//
int group;
int totalBits;
int chunkByteSize;
int chunkNumber;
int ptr = NetFragmentationHelper.ReadHeader(
im.m_data, 0,
out group,
out totalBits,
out chunkByteSize,
out chunkNumber
);
NetException.Assert(im.LengthBytes > ptr);
NetException.Assert(group > 0);
NetException.Assert(totalBits > 0);
NetException.Assert(chunkByteSize > 0);
int totalBytes = NetUtility.BytesToHoldBits((int)totalBits);
int totalNumChunks = totalBytes / chunkByteSize;
if (totalNumChunks * chunkByteSize < totalBytes)
totalNumChunks++;
NetException.Assert(chunkNumber < totalNumChunks);
if (chunkNumber >= totalNumChunks)
{
LogWarning("Index out of bounds for chunk " + chunkNumber + " (total chunks " + totalNumChunks + ")");
return;
}
Dictionary<int, ReceivedFragmentGroup> groups;
if (!m_receivedFragmentGroups.TryGetValue(im.SenderConnection, out groups))
{
groups = new Dictionary<int, ReceivedFragmentGroup>();
m_receivedFragmentGroups[im.SenderConnection] = groups;
}
ReceivedFragmentGroup info;
if (!groups.TryGetValue(group, out info))
{
info = new ReceivedFragmentGroup();
info.Data = new byte[totalBytes];
info.ReceivedChunks = new NetBitVector(totalNumChunks);
groups[group] = info;
}
info.ReceivedChunks[chunkNumber] = true;
info.LastReceived = (float)NetTime.Now;
// copy to data
int offset = (chunkNumber * chunkByteSize);
Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr);
int cnt = info.ReceivedChunks.Count();
LogVerbose("Received fragment " + chunkNumber + " of " + totalNumChunks + " (" + cnt + " chunks received)");
if (info.ReceivedChunks.Count() == totalNumChunks)
{
// Done! Transform this incoming message
im.m_data = info.Data;
im.m_bitLength = (int)totalBits;
im.m_isFragment = false;
LogVerbose("Fragment group #" + group + " fully received in " + totalNumChunks + " chunks (" + totalBits + " bits)");
groups.Remove(group);
ReleaseMessage(im);
}
else
{
// data has been copied; recycle this incoming message
Recycle(im);
}
return;
}
}
}

View File

@@ -1,699 +0,0 @@
#if !__ANDROID__ && !IOS
#define IS_MAC_AVAILABLE
#endif
using System;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Net.Sockets;
using System.Collections.Generic;
namespace Lidgren.Network
{
public partial class NetPeer
{
private NetPeerStatus m_status;
private Thread m_networkThread;
private Socket m_socket;
internal byte[] m_sendBuffer;
internal byte[] m_receiveBuffer;
internal NetIncomingMessage m_readHelperMessage;
private EndPoint m_senderRemote;
private object m_initializeLock = new object();
private uint m_frameCounter;
private double m_lastHeartbeat;
private NetUPnP m_upnp;
internal readonly NetPeerConfiguration m_configuration;
private readonly NetQueue<NetIncomingMessage> m_releasedIncomingMessages;
internal readonly NetQueue<NetTuple<IPEndPoint, NetOutgoingMessage>> m_unsentUnconnectedMessages;
internal Dictionary<IPEndPoint, NetConnection> m_handshakes;
internal readonly NetPeerStatistics m_statistics;
internal long m_uniqueIdentifier;
internal bool m_executeFlushSendQueue;
private AutoResetEvent m_messageReceivedEvent = new AutoResetEvent(false);
private List<NetTuple<SynchronizationContext, SendOrPostCallback>> m_receiveCallbacks;
/// <summary>
/// Gets the socket, if Start() has been called
/// </summary>
public Socket Socket { get { return m_socket; } }
/// <summary>
/// Call this to register a callback for when a new message arrives
/// </summary>
public void RegisterReceivedCallback(SendOrPostCallback callback)
{
if (SynchronizationContext.Current == null)
throw new NetException("Need a SynchronizationContext to register callback on correct thread!");
if (m_receiveCallbacks == null)
m_receiveCallbacks = new List<NetTuple<SynchronizationContext, SendOrPostCallback>>();
m_receiveCallbacks.Add(new NetTuple<SynchronizationContext, SendOrPostCallback>(SynchronizationContext.Current, callback));
}
/// <summary>
/// Call this to unregister a callback, but remember to do it in the same synchronization context!
/// </summary>
public void UnregisterReceivedCallback(SendOrPostCallback callback)
{
if (m_receiveCallbacks == null)
return;
m_receiveCallbacks.Remove(new NetTuple<SynchronizationContext, SendOrPostCallback>(SynchronizationContext.Current, callback));
if (m_receiveCallbacks.Count < 1)
m_receiveCallbacks = null;
}
internal void ReleaseMessage(NetIncomingMessage msg)
{
NetException.Assert(msg.m_incomingMessageType != NetIncomingMessageType.Error);
if (msg.m_isFragment)
{
HandleReleasedFragment(msg);
return;
}
m_releasedIncomingMessages.Enqueue(msg);
if (m_messageReceivedEvent != null)
m_messageReceivedEvent.Set();
if (m_receiveCallbacks != null)
{
foreach (var tuple in m_receiveCallbacks)
tuple.Item1.Post(tuple.Item2, this);
}
}
private void InitializeNetwork()
{
lock (m_initializeLock)
{
m_configuration.Lock();
if (m_status == NetPeerStatus.Running)
return;
if (m_configuration.m_enableUPnP)
m_upnp = new NetUPnP(this);
InitializePools();
m_releasedIncomingMessages.Clear();
m_unsentUnconnectedMessages.Clear();
m_handshakes.Clear();
// bind to socket
IPEndPoint iep = null;
iep = new IPEndPoint(m_configuration.LocalAddress, m_configuration.Port);
EndPoint ep = (EndPoint)iep;
m_socket = new Socket(ep.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
if (ep.AddressFamily == AddressFamily.InterNetworkV6)
{
// Disable IPv4 -> IPv6 mapping.
// SS14 handles IPv6 & IPv4 concurrently with a different net peer.
m_socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, true);
}
m_socket.ReceiveBufferSize = m_configuration.ReceiveBufferSize;
m_socket.SendBufferSize = m_configuration.SendBufferSize;
m_socket.Blocking = false;
m_socket.Bind(ep);
var platform = Environment.OSVersion.Platform;
if (platform != PlatformID.MacOSX && platform != PlatformID.Unix)
{
try
{
const uint IOC_IN = 0x80000000;
const uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
}
catch
{
// ignore; SIO_UDP_CONNRESET not supported on this platform
}
}
IPEndPoint boundEp = m_socket.LocalEndPoint as IPEndPoint;
LogDebug("Socket bound to " + boundEp + ": " + m_socket.IsBound);
m_listenPort = boundEp.Port;
m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize];
m_sendBuffer = new byte[m_configuration.SendBufferSize];
m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error);
m_readHelperMessage.m_data = m_receiveBuffer;
byte[] macBytes = new byte[8];
NetRandom.Instance.NextBytes(macBytes);
#if IS_MAC_AVAILABLE
try
{
System.Net.NetworkInformation.PhysicalAddress pa = NetUtility.GetMacAddress();
if (pa != null)
{
macBytes = pa.GetAddressBytes();
LogVerbose("Mac address is " + NetUtility.ToHexString(macBytes));
}
else
{
LogWarning("Failed to get Mac address");
}
}
catch (NotSupportedException)
{
// not supported; lets just keep the random bytes set above
}
#endif
byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode());
byte[] combined = new byte[epBytes.Length + macBytes.Length];
Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
m_uniqueIdentifier = BitConverter.ToInt64(SHA1.Create().ComputeHash(combined), 0);
m_status = NetPeerStatus.Running;
}
}
private void NetworkLoop()
{
VerifyNetworkThread();
LogDebug("Network thread started");
//
// Network loop
//
do
{
try
{
Heartbeat();
}
catch (Exception ex)
{
LogWarning(ex.ToString());
}
} while (m_status == NetPeerStatus.Running);
//
// perform shutdown
//
ExecutePeerShutdown();
}
private void ExecutePeerShutdown()
{
VerifyNetworkThread();
LogDebug("Shutting down...");
// disconnect and make one final heartbeat
var list = new List<NetConnection>(m_handshakes.Count + m_connections.Count);
lock (m_connections)
{
foreach (var conn in m_connections)
if (conn != null)
list.Add(conn);
lock (m_handshakes)
{
foreach (var hs in m_handshakes.Values)
if (hs != null)
list.Add(hs);
// shut down connections
foreach (NetConnection conn in list)
conn.Shutdown(m_shutdownReason);
}
}
FlushDelayedPackets();
// one final heartbeat, will send stuff and do disconnect
Heartbeat();
Thread.Sleep(10);
lock (m_initializeLock)
{
try
{
if (m_socket != null)
{
try
{
m_socket.Shutdown(SocketShutdown.Receive);
}
catch { }
m_socket.Close(2); // 2 seconds timeout
}
if (m_messageReceivedEvent != null)
{
try
{
m_messageReceivedEvent.Set();
m_messageReceivedEvent.Close();
}
catch (ObjectDisposedException)
{
// For some reason, inside Godot this seems to throw ObjectDisposedExceptions on client shutdown.
// If it's already disposed then I guess this is fine?
}
finally
{
m_messageReceivedEvent = null;
}
}
}
finally
{
m_socket = null;
m_status = NetPeerStatus.NotRunning;
LogDebug("Shutdown complete");
}
m_receiveBuffer = null;
m_sendBuffer = null;
m_unsentUnconnectedMessages.Clear();
m_connections.Clear();
m_handshakes.Clear();
}
return;
}
private void Heartbeat()
{
VerifyNetworkThread();
double dnow = NetTime.Now;
float now = (float)dnow;
double delta = dnow - m_lastHeartbeat;
int maxCHBpS = 1250 - m_connections.Count;
if (maxCHBpS < 250)
maxCHBpS = 250;
if (delta > (1.0 / (double)maxCHBpS) || delta < 0.0) // max connection heartbeats/second max
{
m_frameCounter++;
m_lastHeartbeat = dnow;
// do handshake heartbeats
if ((m_frameCounter % 3) == 0)
{
foreach (var kvp in m_handshakes)
{
NetConnection conn = kvp.Value as NetConnection;
#if DEBUG
// sanity check
if (kvp.Key != kvp.Key)
LogWarning("Sanity fail! Connection in handshake list under wrong key!");
#endif
conn.UnconnectedHeartbeat(now);
if (conn.m_status == NetConnectionStatus.Connected || conn.m_status == NetConnectionStatus.Disconnected)
{
#if DEBUG
// sanity check
if (conn.m_status == NetConnectionStatus.Disconnected && m_handshakes.ContainsKey(conn.RemoteEndPoint))
{
LogWarning("Sanity fail! Handshakes list contained disconnected connection!");
m_handshakes.Remove(conn.RemoteEndPoint);
}
#endif
break; // collection has been modified
}
}
}
#if DEBUG
SendDelayedPackets();
#endif
// update m_executeFlushSendQueue
if (m_configuration.m_autoFlushSendQueue)
m_executeFlushSendQueue = true;
// do connection heartbeats
lock (m_connections)
{
foreach (NetConnection conn in m_connections)
{
conn.Heartbeat(now, m_frameCounter);
if (conn.m_status == NetConnectionStatus.Disconnected)
{
//
// remove connection
//
m_connections.Remove(conn);
m_connectionLookup.Remove(conn.RemoteEndPoint);
break; // can't continue iteration here
}
}
}
m_executeFlushSendQueue = false;
// send unsent unconnected messages
NetTuple<IPEndPoint, NetOutgoingMessage> unsent;
while (m_unsentUnconnectedMessages.TryDequeue(out unsent))
{
NetOutgoingMessage om = unsent.Item2;
bool connReset;
int len = om.Encode(m_sendBuffer, 0, 0);
SendPacket(len, unsent.Item1, 1, out connReset);
Interlocked.Decrement(ref om.m_recyclingCount);
if (om.m_recyclingCount <= 0)
Recycle(om);
}
}
//
// read from socket
//
if (m_socket == null)
return;
if (!m_socket.Poll(1000, SelectMode.SelectRead)) // wait up to 1 ms for data to arrive
return;
do
{
int bytesReceived = 0;
try
{
bytesReceived = m_socket.ReceiveFrom(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, ref m_senderRemote);
}
catch (SocketException sx)
{
if (sx.SocketErrorCode == SocketError.ConnectionReset)
{
// connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
// we should shut down the connection; but m_senderRemote seemingly cannot be trusted, so which connection should we shut down?!
// So, what to do?
LogWarning("ConnectionReset");
return;
}
LogWarning(sx.ToString());
return;
}
if (bytesReceived < NetConstants.HeaderByteSize)
return;
IPEndPoint ipsender = (IPEndPoint)m_senderRemote;
if (ipsender.Port == 1900)
{
// UPnP response
try
{
string resp = System.Text.Encoding.ASCII.GetString(m_receiveBuffer, 0, bytesReceived);
if (resp.Contains("upnp:rootdevice"))
{
resp = resp.Substring(resp.ToLower().IndexOf("location:") + 9);
resp = resp.Substring(0, resp.IndexOf("\r")).Trim();
m_upnp.ExtractServiceUrl(resp);
return;
}
}
catch { }
}
NetConnection sender = null;
m_connectionLookup.TryGetValue(ipsender, out sender);
double receiveTime = NetTime.Now;
//
// parse packet into messages
//
int numMessages = 0;
int ptr = 0;
while ((bytesReceived - ptr) >= NetConstants.HeaderByteSize)
{
// decode header
// 8 bits - NetMessageType
// 1 bit - Fragment?
// 15 bits - Sequence number
// 16 bits - Payload length in bits
numMessages++;
NetMessageType tp = (NetMessageType)m_receiveBuffer[ptr++];
byte low = m_receiveBuffer[ptr++];
byte high = m_receiveBuffer[ptr++];
bool isFragment = ((low & 1) == 1);
ushort sequenceNumber = (ushort)((low >> 1) | (((int)high) << 7));
ushort payloadBitLength = (ushort)(m_receiveBuffer[ptr++] | (m_receiveBuffer[ptr++] << 8));
int payloadByteLength = NetUtility.BytesToHoldBits(payloadBitLength);
if (bytesReceived - ptr < payloadByteLength)
{
LogWarning("Malformed packet; stated payload length " + payloadByteLength + ", remaining bytes " + (bytesReceived - ptr));
return;
}
try
{
NetException.Assert(tp < NetMessageType.Unused1 || tp > NetMessageType.Unused29);
if (tp >= NetMessageType.LibraryError)
{
if (sender != null)
sender.ReceivedLibraryMessage(tp, ptr, payloadByteLength);
else
ReceivedUnconnectedLibraryMessage(receiveTime, ipsender, tp, ptr, payloadByteLength);
}
else
{
if (sender == null && !m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData))
return; // dropping unconnected message since it's not enabled
NetIncomingMessage msg = CreateIncomingMessage(NetIncomingMessageType.Data, payloadByteLength);
msg.m_isFragment = isFragment;
msg.m_receiveTime = receiveTime;
msg.m_sequenceNumber = sequenceNumber;
msg.m_receivedMessageType = tp;
msg.m_senderConnection = sender;
msg.m_senderEndPoint = ipsender;
msg.m_bitLength = payloadBitLength;
Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
if (sender != null)
{
if (tp == NetMessageType.Unconnected)
{
// We're connected; but we can still send unconnected messages to this peer
msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
ReleaseMessage(msg);
}
else
{
// connected application (non-library) message
sender.ReceivedMessage(msg);
}
}
else
{
// at this point we know the message type is enabled
// unconnected application (non-library) message
msg.m_incomingMessageType = NetIncomingMessageType.UnconnectedData;
ReleaseMessage(msg);
}
}
}
catch (Exception ex)
{
LogError("Packet parsing error: " + ex.Message + " from " + ipsender);
}
ptr += payloadByteLength;
}
m_statistics.PacketReceived(bytesReceived, numMessages);
if (sender != null)
sender.m_statistics.PacketReceived(bytesReceived, numMessages);
} while (m_socket.Available > 0);
}
/// <summary>
/// If NetPeerConfiguration.AutoFlushSendQueue() is false; you need to call this to send all messages queued using SendMessage()
/// </summary>
public void FlushSendQueue()
{
m_executeFlushSendQueue = true;
}
internal void HandleIncomingDiscoveryRequest(double now, IPEndPoint senderEndPoint, int ptr, int payloadByteLength)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryRequest))
{
NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadByteLength);
if (payloadByteLength > 0)
Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength);
dm.m_receiveTime = now;
dm.m_bitLength = payloadByteLength * 8;
dm.m_senderEndPoint = senderEndPoint;
ReleaseMessage(dm);
}
}
internal void HandleIncomingDiscoveryResponse(double now, IPEndPoint senderEndPoint, int ptr, int payloadByteLength)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DiscoveryResponse))
{
NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadByteLength);
if (payloadByteLength > 0)
Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength);
dr.m_receiveTime = now;
dr.m_bitLength = payloadByteLength * 8;
dr.m_senderEndPoint = senderEndPoint;
ReleaseMessage(dr);
}
}
private void ReceivedUnconnectedLibraryMessage(double now, IPEndPoint senderEndPoint, NetMessageType tp, int ptr, int payloadByteLength)
{
NetConnection shake;
if (m_handshakes.TryGetValue(senderEndPoint, out shake))
{
shake.ReceivedHandshake(now, tp, ptr, payloadByteLength);
return;
}
//
// Library message from a completely unknown sender; lets just accept Connect
//
switch (tp)
{
case NetMessageType.Discovery:
HandleIncomingDiscoveryRequest(now, senderEndPoint, ptr, payloadByteLength);
return;
case NetMessageType.DiscoveryResponse:
HandleIncomingDiscoveryResponse(now, senderEndPoint, ptr, payloadByteLength);
return;
case NetMessageType.NatIntroduction:
HandleNatIntroduction(ptr);
return;
case NetMessageType.NatPunchMessage:
HandleNatPunch(ptr, senderEndPoint);
return;
case NetMessageType.ConnectResponse:
lock (m_handshakes)
{
foreach (var hs in m_handshakes)
{
if (hs.Key.Address.Equals(senderEndPoint.Address))
{
if (hs.Value.m_connectionInitiator)
{
//
// We are currently trying to connection to XX.XX.XX.XX:Y
// ... but we just received a ConnectResponse from XX.XX.XX.XX:Z
// Lets just assume the router decided to use this port instead
//
var hsconn = hs.Value;
m_connectionLookup.Remove(hs.Key);
m_handshakes.Remove(hs.Key);
LogDebug("Detected host port change; rerouting connection to " + senderEndPoint);
hsconn.MutateEndPoint(senderEndPoint);
m_connectionLookup.Add(senderEndPoint, hsconn);
m_handshakes.Add(senderEndPoint, hsconn);
hsconn.ReceivedHandshake(now, tp, ptr, payloadByteLength);
return;
}
}
}
}
LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint);
return;
case NetMessageType.Connect:
// proceed
break;
case NetMessageType.Disconnect:
// this is probably ok
LogVerbose("Received Disconnect from unconnected source: " + senderEndPoint);
return;
default:
LogWarning("Received unhandled library message " + tp + " from " + senderEndPoint);
return;
}
// It's someone wanting to shake hands with us!
int reservedSlots = m_handshakes.Count + m_connections.Count;
if (reservedSlots >= m_configuration.m_maximumConnections)
{
// server full
NetOutgoingMessage full = CreateMessage("Server full");
full.m_messageType = NetMessageType.Disconnect;
SendLibrary(full, senderEndPoint);
return;
}
// Ok, start handshake!
NetConnection conn = new NetConnection(this, senderEndPoint);
conn.m_status = NetConnectionStatus.ReceivedInitiation;
m_handshakes.Add(senderEndPoint, conn);
conn.ReceivedHandshake(now, tp, ptr, payloadByteLength);
return;
}
internal void AcceptConnection(NetConnection conn)
{
conn.InitExpandMTU(NetTime.Now);
if (m_handshakes.Remove(conn.m_remoteEndPoint) == false)
LogWarning("AcceptConnection called but m_handshakes did not contain it!");
lock (m_connections)
{
if (m_connections.Contains(conn))
{
LogWarning("AcceptConnection called but m_connection already contains it!");
}
else
{
m_connections.Add(conn);
m_connectionLookup.Add(conn.m_remoteEndPoint, conn);
}
}
}
[Conditional("DEBUG")]
internal void VerifyNetworkThread()
{
Thread ct = Thread.CurrentThread;
if (Thread.CurrentThread != m_networkThread)
throw new NetException("Executing on wrong thread! Should be library system thread (is " + ct.Name + " mId " + ct.ManagedThreadId + ")");
}
internal NetIncomingMessage SetupReadHelperMessage(int ptr, int payloadLength)
{
VerifyNetworkThread();
m_readHelperMessage.m_bitLength = (ptr + payloadLength) * 8;
m_readHelperMessage.m_readPosition = (ptr * 8);
return m_readHelperMessage;
}
}
}

View File

@@ -1,299 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//#define USE_RELEASE_STATISTICS
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
namespace Lidgren.Network
{
public partial class NetPeer
{
#if DEBUG
private readonly List<DelayedPacket> m_delayedPackets = new List<DelayedPacket>();
private class DelayedPacket
{
public byte[] Data;
public double DelayedUntil;
public IPEndPoint Target;
}
internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset)
{
connectionReset = false;
// simulate loss
float loss = m_configuration.m_loss;
if (loss > 0.0f)
{
if ((float)NetRandom.Instance.NextDouble() < loss)
{
LogVerbose("Sending packet " + numBytes + " bytes - SIMULATED LOST!");
return; // packet "lost"
}
}
m_statistics.PacketSent(numBytes, numMessages);
// simulate latency
float m = m_configuration.m_minimumOneWayLatency;
float r = m_configuration.m_randomOneWayLatency;
if (m == 0.0f && r == 0.0f)
{
// no latency simulation
bool wasSent = ActuallySendPacket(m_sendBuffer, numBytes, target, out connectionReset);
// TODO: handle wasSent == false?
return;
}
int num = 1;
if (m_configuration.m_duplicates > 0.0f && NetRandom.Instance.NextSingle() < m_configuration.m_duplicates)
num++;
float delay = 0;
for (int i = 0; i < num; i++)
{
delay = m_configuration.m_minimumOneWayLatency + (NetRandom.Instance.NextSingle() * m_configuration.m_randomOneWayLatency);
// Enqueue delayed packet
DelayedPacket p = new DelayedPacket();
p.Target = target;
p.Data = new byte[numBytes];
Buffer.BlockCopy(m_sendBuffer, 0, p.Data, 0, numBytes);
p.DelayedUntil = NetTime.Now + delay;
m_delayedPackets.Add(p);
}
}
private void SendDelayedPackets()
{
if (m_delayedPackets.Count <= 0)
return;
double now = NetTime.Now;
bool connectionReset;
RestartDelaySending:
foreach (DelayedPacket p in m_delayedPackets)
{
if (now > p.DelayedUntil)
{
ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset);
m_delayedPackets.Remove(p);
goto RestartDelaySending;
}
}
}
private void FlushDelayedPackets()
{
try
{
bool connectionReset;
foreach (DelayedPacket p in m_delayedPackets)
ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset);
m_delayedPackets.Clear();
}
catch { }
}
internal bool ActuallySendPacket(byte[] data, int numBytes, IPEndPoint target, out bool connectionReset)
{
connectionReset = false;
try
{
// TODO: refactor this check outta here
if (target.Address == IPAddress.Broadcast)
{
// Some networks do not allow
// a global broadcast so we use the BroadcastAddress from the configuration
// this can be resolved to a local broadcast addresss e.g 192.168.x.255
target.Address = m_configuration.BroadcastAddress;
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
}
int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, target);
if (numBytes != bytesSent)
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
}
catch (SocketException sx)
{
if (sx.SocketErrorCode == SocketError.WouldBlock)
{
// send buffer full?
LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration");
return false;
}
if (sx.SocketErrorCode == SocketError.ConnectionReset)
{
// connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
connectionReset = true;
return false;
}
LogError("Failed to send packet: " + sx);
}
catch (Exception ex)
{
LogError("Failed to send packet: " + ex);
}
finally
{
if (target.Address == IPAddress.Broadcast)
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
}
return true;
}
internal bool SendMTUPacket(int numBytes, IPEndPoint target)
{
try
{
m_socket.DontFragment = true;
int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target);
if (numBytes != bytesSent)
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
m_statistics.PacketSent(numBytes, 1);
}
catch (SocketException sx)
{
if (sx.SocketErrorCode == SocketError.MessageSize)
return false;
if (sx.SocketErrorCode == SocketError.WouldBlock)
{
// send buffer full?
LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration");
return true;
}
if (sx.SocketErrorCode == SocketError.ConnectionReset)
return true;
LogError("Failed to send packet: (" + sx.SocketErrorCode + ") " + sx);
}
catch (Exception ex)
{
LogError("Failed to send packet: " + ex);
}
finally
{
m_socket.DontFragment = false;
}
return true;
}
#else
internal bool SendMTUPacket(int numBytes, IPEndPoint target)
{
try
{
m_socket.DontFragment = true;
int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target);
if (numBytes != bytesSent)
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
}
catch (SocketException sx)
{
if (sx.SocketErrorCode == SocketError.MessageSize)
return false;
if (sx.SocketErrorCode == SocketError.WouldBlock)
{
// send buffer full?
LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration");
return true;
}
if (sx.SocketErrorCode == SocketError.ConnectionReset)
return true;
LogError("Failed to send packet: (" + sx.SocketErrorCode + ") " + sx);
}
catch (Exception ex)
{
LogError("Failed to send packet: " + ex);
}
finally
{
m_socket.DontFragment = false;
}
return true;
}
//
// Release - just send the packet straight away
//
internal void SendPacket(int numBytes, IPEndPoint target, int numMessages, out bool connectionReset)
{
#if USE_RELEASE_STATISTICS
m_statistics.PacketSent(numBytes, numMessages);
#endif
connectionReset = false;
try
{
// TODO: refactor this check outta here
if (target.Address == IPAddress.Broadcast)
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
int bytesSent = m_socket.SendTo(m_sendBuffer, 0, numBytes, SocketFlags.None, target);
if (numBytes != bytesSent)
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
}
catch (SocketException sx)
{
if (sx.SocketErrorCode == SocketError.WouldBlock)
{
// send buffer full?
LogWarning("Socket threw exception; would block - send buffer full? Increase in NetPeerConfiguration");
return;
}
if (sx.SocketErrorCode == SocketError.ConnectionReset)
{
// connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable"
connectionReset = true;
return;
}
LogError("Failed to send packet: " + sx);
}
catch (Exception ex)
{
LogError("Failed to send packet: " + ex);
}
finally
{
if (target.Address == IPAddress.Broadcast)
m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
}
return;
}
private void FlushDelayedPackets()
{
}
private void SendCallBack(IAsyncResult res)
{
NetException.Assert(res.IsCompleted == true);
m_socket.EndSendTo(res);
}
#endif
}
}

View File

@@ -1,51 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System.Diagnostics;
namespace Lidgren.Network
{
public partial class NetPeer
{
[Conditional("DEBUG")]
internal void LogVerbose(string message)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.VerboseDebugMessage))
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.VerboseDebugMessage, message));
}
[Conditional("DEBUG")]
internal void LogDebug(string message)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.DebugMessage))
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.DebugMessage, message));
}
internal void LogWarning(string message)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.WarningMessage))
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.WarningMessage, message));
}
internal void LogError(string message)
{
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.ErrorMessage))
ReleaseMessage(CreateIncomingMessage(NetIncomingMessageType.ErrorMessage, message));
}
}
}

View File

@@ -1,228 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Lidgren.Network
{
public partial class NetPeer
{
private List<byte[]> m_storagePool; // sorted smallest to largest
private NetQueue<NetOutgoingMessage> m_outgoingMessagesPool;
private NetQueue<NetIncomingMessage> m_incomingMessagesPool;
internal int m_storagePoolBytes;
private void InitializePools()
{
if (m_configuration.UseMessageRecycling)
{
m_storagePool = new List<byte[]>(16);
m_outgoingMessagesPool = new NetQueue<NetOutgoingMessage>(4);
m_incomingMessagesPool = new NetQueue<NetIncomingMessage>(4);
}
else
{
m_storagePool = null;
m_outgoingMessagesPool = null;
m_incomingMessagesPool = null;
}
}
internal byte[] GetStorage(int minimumCapacityInBytes)
{
if (m_storagePool == null)
return new byte[minimumCapacityInBytes];
lock (m_storagePool)
{
for (int i = 0; i < m_storagePool.Count; i++)
{
byte[] retval = m_storagePool[i];
if (retval != null && retval.Length >= minimumCapacityInBytes)
{
m_storagePool[i] = null;
m_storagePoolBytes -= retval.Length;
return retval;
}
}
}
m_statistics.m_bytesAllocated += minimumCapacityInBytes;
return new byte[minimumCapacityInBytes];
}
internal void Recycle(byte[] storage)
{
if (m_storagePool == null)
return;
lock (m_storagePool)
{
m_storagePoolBytes += storage.Length;
int cnt = m_storagePool.Count;
for (int i = 0; i < cnt; i++)
{
if (m_storagePool[i] == null)
{
m_storagePool[i] = storage;
return;
}
}
m_storagePool.Add(storage);
}
}
/// <summary>
/// Creates a new message for sending
/// </summary>
public NetOutgoingMessage CreateMessage()
{
return CreateMessage(m_configuration.m_defaultOutgoingMessageCapacity);
}
/// <summary>
/// Creates a new message for sending and writes the provided string to it
/// </summary>
public NetOutgoingMessage CreateMessage(string content)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
NetOutgoingMessage om = CreateMessage(2 + bytes.Length);
om.WriteVariableUInt32((uint)bytes.Length);
om.Write(bytes);
return om;
}
/// <summary>
/// Creates a new message for sending
/// </summary>
/// <param name="initialCapacity">initial capacity in bytes</param>
public NetOutgoingMessage CreateMessage(int initialCapacity)
{
NetOutgoingMessage retval;
if (m_outgoingMessagesPool == null || !m_outgoingMessagesPool.TryDequeue(out retval))
retval = new NetOutgoingMessage();
byte[] storage = GetStorage(initialCapacity);
retval.m_data = storage;
return retval;
}
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, byte[] useStorageData)
{
NetIncomingMessage retval;
if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval))
retval = new NetIncomingMessage(tp);
else
retval.m_incomingMessageType = tp;
retval.m_data = useStorageData;
return retval;
}
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, int minimumByteSize)
{
NetIncomingMessage retval;
if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval))
retval = new NetIncomingMessage(tp);
else
retval.m_incomingMessageType = tp;
retval.m_data = GetStorage(minimumByteSize);
return retval;
}
/// <summary>
/// Recycles a NetIncomingMessage instance for reuse; taking pressure off the garbage collector
/// </summary>
public void Recycle(NetIncomingMessage msg)
{
if (m_incomingMessagesPool == null)
return;
#if DEBUG
if (m_incomingMessagesPool.Contains(msg))
throw new NetException("Recyling already recycled message! Thread race?");
#endif
byte[] storage = msg.m_data;
msg.m_data = null;
Recycle(storage);
msg.Reset();
m_incomingMessagesPool.Enqueue(msg);
}
/// <summary>
/// Recycles a list of NetIncomingMessage instances for reuse; taking pressure off the garbage collector
/// </summary>
public void Recycle(IEnumerable<NetIncomingMessage> toRecycle)
{
if (m_incomingMessagesPool == null)
return;
// first recycle the storage of each message
if (m_storagePool != null)
{
lock (m_storagePool)
{
foreach (var msg in toRecycle)
{
var storage = msg.m_data;
msg.m_data = null;
m_storagePoolBytes += storage.Length;
int cnt = m_storagePool.Count;
for (int i = 0; i < cnt; i++)
{
if (m_storagePool[i] == null)
{
m_storagePool[i] = storage;
return;
}
}
msg.Reset();
m_storagePool.Add(storage);
}
}
}
// then recycle the message objects
m_incomingMessagesPool.Enqueue(toRecycle);
}
internal void Recycle(NetOutgoingMessage msg)
{
if (m_outgoingMessagesPool == null)
return;
#if DEBUG
if (m_outgoingMessagesPool.Contains(msg))
throw new NetException("Recyling already recycled message! Thread race?");
#endif
byte[] storage = msg.m_data;
msg.m_data = null;
// message fragments cannot be recycled
// TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them
if (msg.m_fragmentGroup == 0)
Recycle(storage);
msg.Reset();
m_outgoingMessagesPool.Enqueue(msg);
}
/// <summary>
/// Creates an incoming message with the required capacity for releasing to the application
/// </summary>
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, string text)
{
NetIncomingMessage retval;
if (string.IsNullOrEmpty(text))
{
retval = CreateIncomingMessage(tp, 1);
retval.Write(string.Empty);
return retval;
}
int numBytes = System.Text.Encoding.UTF8.GetByteCount(text);
retval = CreateIncomingMessage(tp, numBytes + (numBytes > 127 ? 2 : 1));
retval.Write(text);
return retval;
}
}
}

View File

@@ -1,226 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Net;
namespace Lidgren.Network
{
public partial class NetPeer
{
/// <summary>
/// Send a message to a specific connection
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="recipient">The recipient connection</param>
/// <param name="method">How to deliver the message</param>
public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method)
{
return SendMessage(msg, recipient, method, 0);
}
/// <summary>
/// Send a message to a specific connection
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="recipient">The recipient connection</param>
/// <param name="method">How to deliver the message</param>
/// <param name="sequenceChannel">Sequence channel within the delivery method</param>
public NetSendResult SendMessage(NetOutgoingMessage msg, NetConnection recipient, NetDeliveryMethod method, int sequenceChannel)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (recipient == null)
throw new ArgumentNullException("recipient");
if (sequenceChannel >= NetConstants.NetChannelsPerDeliveryMethod)
throw new ArgumentOutOfRangeException("sequenceChannel");
NetException.Assert(
((method != NetDeliveryMethod.Unreliable && method != NetDeliveryMethod.ReliableUnordered) ||
((method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered) && sequenceChannel == 0)),
"Delivery method " + method + " cannot use sequence channels other than 0!"
);
NetException.Assert(method != NetDeliveryMethod.Unknown, "Bad delivery method!");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
msg.m_isSent = true;
int len = NetConstants.UnfragmentedMessageHeaderSize + msg.LengthBytes; // headers + length, faster than calling msg.GetEncodedSize
if (len <= recipient.m_currentMTU)
{
Interlocked.Increment(ref msg.m_recyclingCount);
return recipient.EnqueueMessage(msg, method, sequenceChannel);
}
else
{
// message must be fragmented!
if (recipient.m_status != NetConnectionStatus.Connected)
return NetSendResult.FailedNotConnected;
SendFragmentedMessage(msg, new NetConnection[] { recipient }, method, sequenceChannel);
return NetSendResult.Queued; // could be different for each connection; Queued is "most true"
}
}
internal int GetMTU(IList<NetConnection> recipients)
{
int count = recipients.Count;
NetException.Assert(count > 0);
int mtu = int.MaxValue;
for(int i=0;i<count;i++)
{
var conn = recipients[i];
int cmtu = conn.m_currentMTU;
if (cmtu < mtu)
mtu = cmtu;
}
return mtu;
}
/// <summary>
/// Send a message to a list of connections
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="recipients">The list of recipients to send to</param>
/// <param name="method">How to deliver the message</param>
/// <param name="sequenceChannel">Sequence channel within the delivery method</param>
public void SendMessage(NetOutgoingMessage msg, List<NetConnection> recipients, NetDeliveryMethod method, int sequenceChannel)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (recipients == null)
throw new ArgumentNullException("recipients");
if (recipients.Count < 1)
throw new NetException("recipients must contain at least one item");
if (method == NetDeliveryMethod.Unreliable || method == NetDeliveryMethod.ReliableUnordered)
NetException.Assert(sequenceChannel == 0, "Delivery method " + method + " cannot use sequence channels other than 0!");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
int mtu = GetMTU(recipients);
msg.m_isSent = true;
int len = msg.GetEncodedSize();
if (len <= mtu)
{
Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
foreach (NetConnection conn in recipients)
{
if (conn == null)
{
Interlocked.Decrement(ref msg.m_recyclingCount);
continue;
}
NetSendResult res = conn.EnqueueMessage(msg, method, sequenceChannel);
if (res != NetSendResult.Queued && res != NetSendResult.Sent)
Interlocked.Decrement(ref msg.m_recyclingCount);
}
}
else
{
// message must be fragmented!
SendFragmentedMessage(msg, recipients, method, sequenceChannel);
}
return;
}
/// <summary>
/// Send a message to an unconnected host
/// </summary>
public void SendUnconnectedMessage(NetOutgoingMessage msg, string host, int port)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (host == null)
throw new ArgumentNullException("host");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit)
throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")");
IPAddress adr = NetUtility.Resolve(host);
if (adr == null)
throw new NetException("Failed to resolve " + host);
msg.m_messageType = NetMessageType.Unconnected;
msg.m_isSent = true;
Interlocked.Increment(ref msg.m_recyclingCount);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(new IPEndPoint(adr, port), msg));
}
/// <summary>
/// Send a message to an unconnected host
/// </summary>
public void SendUnconnectedMessage(NetOutgoingMessage msg, IPEndPoint recipient)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (recipient == null)
throw new ArgumentNullException("recipient");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit)
throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")");
msg.m_messageType = NetMessageType.Unconnected;
msg.m_isSent = true;
Interlocked.Increment(ref msg.m_recyclingCount);
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(recipient, msg));
}
/// <summary>
/// Send a message to an unconnected host
/// </summary>
public void SendUnconnectedMessage(NetOutgoingMessage msg, IList<IPEndPoint> recipients)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (recipients == null)
throw new ArgumentNullException("recipients");
if (recipients.Count < 1)
throw new NetException("recipients must contain at least one item");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
if (msg.LengthBytes > m_configuration.MaximumTransmissionUnit)
throw new NetException("Unconnected messages too long! Must be shorter than NetConfiguration.MaximumTransmissionUnit (currently " + m_configuration.MaximumTransmissionUnit + ")");
msg.m_messageType = NetMessageType.Unconnected;
msg.m_isSent = true;
Interlocked.Add(ref msg.m_recyclingCount, recipients.Count);
foreach(IPEndPoint ep in recipients)
m_unsentUnconnectedMessages.Enqueue(new NetTuple<IPEndPoint, NetOutgoingMessage>(ep, msg));
}
/// <summary>
/// Send a message to this exact same netpeer (loopback)
/// </summary>
public void SendUnconnectedToSelf(NetOutgoingMessage msg)
{
if (msg == null)
throw new ArgumentNullException("msg");
if (msg.m_isSent)
throw new NetException("This message has already been sent! Use NetPeer.SendMessage() to send to multiple recipients efficiently");
msg.m_messageType = NetMessageType.Unconnected;
msg.m_isSent = true;
if (m_configuration.IsMessageTypeEnabled(NetIncomingMessageType.UnconnectedData) == false)
return; // dropping unconnected message since it's not enabled for receiving
NetIncomingMessage om = CreateIncomingMessage(NetIncomingMessageType.UnconnectedData, msg.LengthBytes);
om.m_isFragment = false;
om.m_receiveTime = NetTime.Now;
om.m_senderConnection = null;
om.m_senderEndPoint = m_socket.LocalEndPoint as IPEndPoint;
om.m_bitLength = msg.LengthBits;
ReleaseMessage(om);
}
}
}

View File

@@ -1,337 +0,0 @@
using System;
using System.Threading;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
namespace Lidgren.Network
{
/// <summary>
/// Represents a local peer capable of holding zero, one or more connections to remote peers
/// </summary>
public partial class NetPeer
{
private static int s_initializedPeersCount;
private int m_listenPort;
private object m_tag;
internal readonly List<NetConnection> m_connections;
private readonly Dictionary<IPEndPoint, NetConnection> m_connectionLookup;
private string m_shutdownReason;
/// <summary>
/// Gets the NetPeerStatus of the NetPeer
/// </summary>
public NetPeerStatus Status { get { return m_status; } }
/// <summary>
/// Signalling event which can be waited on to determine when a message is queued for reading.
/// Note that there is no guarantee that after the event is signaled the blocked thread will
/// find the message in the queue. Other user created threads could be preempted and dequeue
/// the message before the waiting thread wakes up.
/// </summary>
public AutoResetEvent MessageReceivedEvent { get { return m_messageReceivedEvent; } }
/// <summary>
/// Gets a unique identifier for this NetPeer based on Mac address and ip/port. Note! Not available until Start() has been called!
/// </summary>
public long UniqueIdentifier { get { return m_uniqueIdentifier; } }
/// <summary>
/// Gets the port number this NetPeer is listening and sending on, if Start() has been called
/// </summary>
public int Port { get { return m_listenPort; } }
/// <summary>
/// Returns an UPnP object if enabled in the NetPeerConfiguration
/// </summary>
public NetUPnP UPnP { get { return m_upnp; } }
/// <summary>
/// Gets or sets the application defined object containing data about the peer
/// </summary>
public object Tag
{
get { return m_tag; }
set { m_tag = value; }
}
/// <summary>
/// Gets a copy of the list of connections
/// </summary>
public List<NetConnection> Connections
{
get
{
lock (m_connections)
return new List<NetConnection>(m_connections);
}
}
/// <summary>
/// Gets the number of active connections
/// </summary>
public int ConnectionsCount
{
get { return m_connections.Count; }
}
/// <summary>
/// Statistics on this NetPeer since it was initialized
/// </summary>
public NetPeerStatistics Statistics
{
get { return m_statistics; }
}
/// <summary>
/// Gets the configuration used to instanciate this NetPeer
/// </summary>
public NetPeerConfiguration Configuration { get { return m_configuration; } }
/// <summary>
/// NetPeer constructor
/// </summary>
public NetPeer(NetPeerConfiguration config)
{
m_configuration = config;
m_statistics = new NetPeerStatistics(this);
m_releasedIncomingMessages = new NetQueue<NetIncomingMessage>(4);
m_unsentUnconnectedMessages = new NetQueue<NetTuple<IPEndPoint, NetOutgoingMessage>>(2);
m_connections = new List<NetConnection>();
m_connectionLookup = new Dictionary<IPEndPoint, NetConnection>();
m_handshakes = new Dictionary<IPEndPoint, NetConnection>();
if (m_configuration.LocalAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0);
}
else
{
m_senderRemote = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
}
m_status = NetPeerStatus.NotRunning;
m_receivedFragmentGroups = new Dictionary<NetConnection, Dictionary<int, ReceivedFragmentGroup>>();
}
/// <summary>
/// Binds to socket and spawns the networking thread
/// </summary>
public void Start()
{
if (m_status != NetPeerStatus.NotRunning)
{
// already running! Just ignore...
LogWarning("Start() called on already running NetPeer - ignoring.");
return;
}
m_status = NetPeerStatus.Starting;
// fix network thread name
if (m_configuration.NetworkThreadName == "Lidgren network thread")
{
int pc = Interlocked.Increment(ref s_initializedPeersCount);
m_configuration.NetworkThreadName = "Lidgren network thread " + pc.ToString();
}
InitializeNetwork();
// start network thread
m_networkThread = new Thread(new ThreadStart(NetworkLoop));
m_networkThread.Name = m_configuration.NetworkThreadName;
m_networkThread.IsBackground = true;
m_networkThread.Start();
// send upnp discovery
if (m_upnp != null)
m_upnp.Discover(this);
// allow some time for network thread to start up in case they call Connect() or UPnP calls immediately
Thread.Sleep(50);
}
/// <summary>
/// Get the connection, if any, for a certain remote endpoint
/// </summary>
public NetConnection GetConnection(IPEndPoint ep)
{
NetConnection retval;
// this should not pose a threading problem, m_connectionLookup is never added to concurrently
// and TryGetValue will not throw an exception on fail, only yield null, which is acceptable
m_connectionLookup.TryGetValue(ep, out retval);
return retval;
}
/// <summary>
/// Read a pending message from any connection, blocking up to maxMillis if needed
/// </summary>
public NetIncomingMessage WaitMessage(int maxMillis)
{
var msg = ReadMessage();
if (msg != null)
return msg; // no need to wait; we already have a message to deliver
if (m_messageReceivedEvent != null)
m_messageReceivedEvent.WaitOne(maxMillis);
return ReadMessage();
}
/// <summary>
/// Read a pending message from any connection, if any
/// </summary>
public NetIncomingMessage ReadMessage()
{
NetIncomingMessage retval;
if (m_releasedIncomingMessages.TryDequeue(out retval))
{
if (retval.MessageType == NetIncomingMessageType.StatusChanged)
{
NetConnectionStatus status = (NetConnectionStatus)retval.PeekByte();
retval.SenderConnection.m_visibleStatus = status;
}
}
return retval;
}
/// <summary>
/// Read a pending message from any connection, if any
/// </summary>
public int ReadMessages(IList<NetIncomingMessage> addTo)
{
int added = m_releasedIncomingMessages.TryDrain(addTo);
if (added > 0)
{
for (int i = 0; i < added; i++)
{
var index = addTo.Count - added + i;
var nim = addTo[index];
if (nim.MessageType == NetIncomingMessageType.StatusChanged)
{
NetConnectionStatus status = (NetConnectionStatus)nim.PeekByte();
nim.SenderConnection.m_visibleStatus = status;
}
}
}
return added;
}
// send message immediately
internal void SendLibrary(NetOutgoingMessage msg, IPEndPoint recipient)
{
VerifyNetworkThread();
NetException.Assert(msg.m_isSent == false);
bool connReset;
int len = msg.Encode(m_sendBuffer, 0, 0);
SendPacket(len, recipient, 1, out connReset);
}
/// <summary>
/// Create a connection to a remote endpoint
/// </summary>
public NetConnection Connect(string host, int port)
{
return Connect(new IPEndPoint(NetUtility.Resolve(host), port), null);
}
/// <summary>
/// Create a connection to a remote endpoint
/// </summary>
public NetConnection Connect(string host, int port, NetOutgoingMessage hailMessage)
{
return Connect(new IPEndPoint(NetUtility.Resolve(host), port), hailMessage);
}
/// <summary>
/// Create a connection to a remote endpoint
/// </summary>
public NetConnection Connect(IPEndPoint remoteEndPoint)
{
return Connect(remoteEndPoint, null);
}
/// <summary>
/// Create a connection to a remote endpoint
/// </summary>
public virtual NetConnection Connect(IPEndPoint remoteEndPoint, NetOutgoingMessage hailMessage)
{
if (remoteEndPoint == null)
throw new ArgumentNullException("remoteEndPoint");
lock (m_connections)
{
if (m_status == NetPeerStatus.NotRunning)
throw new NetException("Must call Start() first");
if (m_connectionLookup.ContainsKey(remoteEndPoint))
throw new NetException("Already connected to that endpoint!");
NetConnection hs;
if (m_handshakes.TryGetValue(remoteEndPoint, out hs))
{
// already trying to connect to that endpoint; make another try
switch (hs.m_status)
{
case NetConnectionStatus.InitiatedConnect:
// send another connect
hs.m_connectRequested = true;
break;
case NetConnectionStatus.RespondedConnect:
// send another response
hs.SendConnectResponse((float)NetTime.Now, false);
break;
default:
// weird
LogWarning("Weird situation; Connect() already in progress to remote endpoint; but hs status is " + hs.m_status);
break;
}
return hs;
}
NetConnection conn = new NetConnection(this, remoteEndPoint);
conn.m_status = NetConnectionStatus.InitiatedConnect;
conn.m_localHailMessage = hailMessage;
// handle on network thread
conn.m_connectRequested = true;
conn.m_connectionInitiator = true;
m_handshakes.Add(remoteEndPoint, conn);
return conn;
}
}
/// <summary>
/// Send raw bytes; only used for debugging
/// </summary>
#if DEBUG
public void RawSend(byte[] arr, int offset, int length, IPEndPoint destination)
#else
internal void RawSend(byte[] arr, int offset, int length, IPEndPoint destination)
#endif
{
// wrong thread - this miiiight crash with network thread... but what's a boy to do.
Array.Copy(arr, offset, m_sendBuffer, 0, length);
bool unused;
SendPacket(length, destination, 1, out unused);
}
/// <summary>
/// Disconnects all active connections and closes the socket
/// </summary>
public void Shutdown(string bye)
{
// called on user thread
if (m_socket == null)
return; // already shut down
LogDebug("Shutdown requested");
m_shutdownReason = bye;
m_status = NetPeerStatus.ShutdownRequested;
}
}
}

View File

@@ -1,471 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Net;
namespace Lidgren.Network
{
/// <summary>
/// Partly immutable after NetPeer has been initialized
/// </summary>
public sealed class NetPeerConfiguration
{
private const string c_isLockedMessage = "You may not modify the NetPeerConfiguration after it has been used to initialize a NetPeer";
private bool m_isLocked;
private readonly string m_appIdentifier;
private string m_networkThreadName;
private IPAddress m_localAddress;
private IPAddress m_broadcastAddress;
internal bool m_acceptIncomingConnections;
internal int m_maximumConnections;
internal int m_defaultOutgoingMessageCapacity;
internal float m_pingInterval;
internal bool m_useMessageRecycling;
internal float m_connectionTimeout;
internal bool m_enableUPnP;
internal bool m_autoFlushSendQueue;
internal NetIncomingMessageType m_disabledTypes;
internal int m_port;
internal int m_receiveBufferSize;
internal int m_sendBufferSize;
internal float m_resendHandshakeInterval;
internal int m_maximumHandshakeAttempts;
// bad network simulation
internal float m_loss;
internal float m_duplicates;
internal float m_minimumOneWayLatency;
internal float m_randomOneWayLatency;
// MTU
internal int m_maximumTransmissionUnit;
internal bool m_autoExpandMTU;
internal float m_expandMTUFrequency;
internal int m_expandMTUFailAttempts;
/// <summary>
/// NetPeerConfiguration constructor
/// </summary>
public NetPeerConfiguration(string appIdentifier)
{
if (string.IsNullOrEmpty(appIdentifier))
throw new NetException("App identifier must be at least one character long");
m_appIdentifier = appIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture);
//
// default values
//
m_disabledTypes = NetIncomingMessageType.ConnectionApproval | NetIncomingMessageType.UnconnectedData | NetIncomingMessageType.VerboseDebugMessage | NetIncomingMessageType.ConnectionLatencyUpdated;
m_networkThreadName = "Lidgren network thread";
m_localAddress = IPAddress.Any;
m_broadcastAddress = IPAddress.Broadcast;
var ip = NetUtility.GetBroadcastAddress();
if (ip != null)
{
m_broadcastAddress = ip;
}
m_port = 0;
m_receiveBufferSize = 131071;
m_sendBufferSize = 131071;
m_acceptIncomingConnections = false;
m_maximumConnections = 32;
m_defaultOutgoingMessageCapacity = 16;
m_pingInterval = 4.0f;
m_connectionTimeout = 25.0f;
m_useMessageRecycling = true;
m_resendHandshakeInterval = 3.0f;
m_maximumHandshakeAttempts = 5;
m_autoFlushSendQueue = true;
// Maximum transmission unit
// Ethernet can take 1500 bytes of payload, so lets stay below that.
// The aim is for a max full packet to be 1440 bytes (30 x 48 bytes, lower than 1468)
// -20 bytes IP header
// -8 bytes UDP header
// -4 bytes to be on the safe side and align to 8-byte boundary
// Total 1408 bytes
// Note that lidgren headers (5 bytes) are not included here; since it's part of the "mtu payload"
m_maximumTransmissionUnit = 1408;
m_autoExpandMTU = false;
m_expandMTUFrequency = 2.0f;
m_expandMTUFailAttempts = 5;
m_loss = 0.0f;
m_minimumOneWayLatency = 0.0f;
m_randomOneWayLatency = 0.0f;
m_duplicates = 0.0f;
m_isLocked = false;
}
internal void Lock()
{
m_isLocked = true;
}
/// <summary>
/// Gets the identifier of this application; the library can only connect to matching app identifier peers
/// </summary>
public string AppIdentifier
{
get { return m_appIdentifier; }
}
/// <summary>
/// Enables receiving of the specified type of message
/// </summary>
public void EnableMessageType(NetIncomingMessageType type)
{
m_disabledTypes &= (~type);
}
/// <summary>
/// Disables receiving of the specified type of message
/// </summary>
public void DisableMessageType(NetIncomingMessageType type)
{
m_disabledTypes |= type;
}
/// <summary>
/// Enables or disables receiving of the specified type of message
/// </summary>
public void SetMessageTypeEnabled(NetIncomingMessageType type, bool enabled)
{
if (enabled)
m_disabledTypes &= (~type);
else
m_disabledTypes |= type;
}
/// <summary>
/// Gets if receiving of the specified type of message is enabled
/// </summary>
public bool IsMessageTypeEnabled(NetIncomingMessageType type)
{
return !((m_disabledTypes & type) == type);
}
/// <summary>
/// Gets or sets the name of the library network thread. Cannot be changed once NetPeer is initialized.
/// </summary>
public string NetworkThreadName
{
get { return m_networkThreadName; }
set
{
if (m_isLocked)
throw new NetException("NetworkThreadName may not be set after the NetPeer which uses the configuration has been started");
m_networkThreadName = value;
}
}
/// <summary>
/// Gets or sets the maximum amount of connections this peer can hold. Cannot be changed once NetPeer is initialized.
/// </summary>
public int MaximumConnections
{
get { return m_maximumConnections; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_maximumConnections = value;
}
}
/// <summary>
/// Gets or sets the maximum amount of bytes to send in a single packet, excluding ip, udp and lidgren headers. Cannot be changed once NetPeer is initialized.
/// </summary>
public int MaximumTransmissionUnit
{
get { return m_maximumTransmissionUnit; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
if (value < 1 || value >= ((ushort.MaxValue + 1) / 8))
throw new NetException("MaximumTransmissionUnit must be between 1 and " + (((ushort.MaxValue + 1) / 8) - 1) + " bytes");
m_maximumTransmissionUnit = value;
}
}
/// <summary>
/// Gets or sets the default capacity in bytes when NetPeer.CreateMessage() is called without argument
/// </summary>
public int DefaultOutgoingMessageCapacity
{
get { return m_defaultOutgoingMessageCapacity; }
set { m_defaultOutgoingMessageCapacity = value; }
}
/// <summary>
/// Gets or sets the time between latency calculating pings
/// </summary>
public float PingInterval
{
get { return m_pingInterval; }
set { m_pingInterval = value; }
}
/// <summary>
/// Gets or sets if the library should recycling messages to avoid excessive garbage collection. Cannot be changed once NetPeer is initialized.
/// </summary>
public bool UseMessageRecycling
{
get { return m_useMessageRecycling; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_useMessageRecycling = value;
}
}
/// <summary>
/// Gets or sets the number of seconds timeout will be postponed on a successful ping/pong
/// </summary>
public float ConnectionTimeout
{
get { return m_connectionTimeout; }
set
{
if (value < m_pingInterval)
throw new NetException("Connection timeout cannot be lower than ping interval!");
m_connectionTimeout = value;
}
}
/// <summary>
/// Enables UPnP support; enabling port forwarding and getting external ip
/// </summary>
public bool EnableUPnP
{
get { return m_enableUPnP; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_enableUPnP = value;
}
}
/// <summary>
/// Enables or disables automatic flushing of the send queue. If disabled, you must manully call NetPeer.FlushSendQueue() to flush sent messages to network.
/// </summary>
public bool AutoFlushSendQueue
{
get { return m_autoFlushSendQueue; }
set { m_autoFlushSendQueue = value; }
}
/// <summary>
/// Gets or sets the local ip address to bind to. Defaults to IPAddress.Any. Cannot be changed once NetPeer is initialized.
/// </summary>
public IPAddress LocalAddress
{
get { return m_localAddress; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_localAddress = value;
}
}
/// <summary>
/// Gets or sets the local broadcast address to use when broadcasting
/// </summary>
public IPAddress BroadcastAddress
{
get { return m_broadcastAddress; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_broadcastAddress = value;
}
}
/// <summary>
/// Gets or sets the local port to bind to. Defaults to 0. Cannot be changed once NetPeer is initialized.
/// </summary>
public int Port
{
get { return m_port; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_port = value;
}
}
/// <summary>
/// Gets or sets the size in bytes of the receiving buffer. Defaults to 131071 bytes. Cannot be changed once NetPeer is initialized.
/// </summary>
public int ReceiveBufferSize
{
get { return m_receiveBufferSize; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_receiveBufferSize = value;
}
}
/// <summary>
/// Gets or sets the size in bytes of the sending buffer. Defaults to 131071 bytes. Cannot be changed once NetPeer is initialized.
/// </summary>
public int SendBufferSize
{
get { return m_sendBufferSize; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_sendBufferSize = value;
}
}
/// <summary>
/// Gets or sets if the NetPeer should accept incoming connections. This is automatically set to true in NetServer and false in NetClient.
/// </summary>
public bool AcceptIncomingConnections
{
get { return m_acceptIncomingConnections; }
set { m_acceptIncomingConnections = value; }
}
/// <summary>
/// Gets or sets the number of seconds between handshake attempts
/// </summary>
public float ResendHandshakeInterval
{
get { return m_resendHandshakeInterval; }
set { m_resendHandshakeInterval = value; }
}
/// <summary>
/// Gets or sets the maximum number of handshake attempts before failing to connect
/// </summary>
public int MaximumHandshakeAttempts
{
get { return m_maximumHandshakeAttempts; }
set
{
if (value < 1)
throw new NetException("MaximumHandshakeAttempts must be at least 1");
m_maximumHandshakeAttempts = value;
}
}
/// <summary>
/// Gets or sets if the NetPeer should send large messages to try to expand the maximum transmission unit size
/// </summary>
public bool AutoExpandMTU
{
get { return m_autoExpandMTU; }
set
{
if (m_isLocked)
throw new NetException(c_isLockedMessage);
m_autoExpandMTU = value;
}
}
/// <summary>
/// Gets or sets how often to send large messages to expand MTU if AutoExpandMTU is enabled
/// </summary>
public float ExpandMTUFrequency
{
get { return m_expandMTUFrequency; }
set { m_expandMTUFrequency = value; }
}
/// <summary>
/// Gets or sets the number of failed expand mtu attempts to perform before setting final MTU
/// </summary>
public int ExpandMTUFailAttempts
{
get { return m_expandMTUFailAttempts; }
set { m_expandMTUFailAttempts = value; }
}
#if DEBUG
/// <summary>
/// Gets or sets the simulated amount of sent packets lost from 0.0f to 1.0f
/// </summary>
public float SimulatedLoss
{
get { return m_loss; }
set { m_loss = value; }
}
/// <summary>
/// Gets or sets the minimum simulated amount of one way latency for sent packets in seconds
/// </summary>
public float SimulatedMinimumLatency
{
get { return m_minimumOneWayLatency; }
set { m_minimumOneWayLatency = value; }
}
/// <summary>
/// Gets or sets the simulated added random amount of one way latency for sent packets in seconds
/// </summary>
public float SimulatedRandomLatency
{
get { return m_randomOneWayLatency; }
set { m_randomOneWayLatency = value; }
}
/// <summary>
/// Gets the average simulated one way latency in seconds
/// </summary>
public float SimulatedAverageLatency
{
get { return m_minimumOneWayLatency + (m_randomOneWayLatency * 0.5f); }
}
/// <summary>
/// Gets or sets the simulated amount of duplicated packets from 0.0f to 1.0f
/// </summary>
public float SimulatedDuplicatesChance
{
get { return m_duplicates; }
set { m_duplicates = value; }
}
#endif
/// <summary>
/// Creates a memberwise shallow clone of this configuration
/// </summary>
public NetPeerConfiguration Clone()
{
NetPeerConfiguration retval = this.MemberwiseClone() as NetPeerConfiguration;
retval.m_isLocked = false;
return retval;
}
}
}

View File

@@ -1,161 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// Uncomment the line below to get statistics in RELEASE builds
#define USE_RELEASE_STATISTICS
using System;
using System.Text;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Statistics for a NetPeer instance
/// </summary>
public sealed class NetPeerStatistics
{
private readonly NetPeer m_peer;
internal int m_sentPackets;
internal int m_receivedPackets;
internal int m_sentMessages;
internal int m_receivedMessages;
internal int m_sentBytes;
internal int m_receivedBytes;
internal long m_bytesAllocated;
internal NetPeerStatistics(NetPeer peer)
{
m_peer = peer;
Reset();
}
internal void Reset()
{
m_sentPackets = 0;
m_receivedPackets = 0;
m_sentMessages = 0;
m_receivedMessages = 0;
m_sentBytes = 0;
m_receivedBytes = 0;
m_bytesAllocated = 0;
}
/// <summary>
/// Gets the number of sent packets since the NetPeer was initialized
/// </summary>
public int SentPackets { get { return m_sentPackets; } }
/// <summary>
/// Gets the number of received packets since the NetPeer was initialized
/// </summary>
public int ReceivedPackets { get { return m_receivedPackets; } }
/// <summary>
/// Gets the number of sent messages since the NetPeer was initialized
/// </summary>
public int SentMessages { get { return m_sentMessages; } }
/// <summary>
/// Gets the number of received messages since the NetPeer was initialized
/// </summary>
public int ReceivedMessages { get { return m_receivedMessages; } }
/// <summary>
/// Gets the number of sent bytes since the NetPeer was initialized
/// </summary>
public int SentBytes { get { return m_sentBytes; } }
/// <summary>
/// Gets the number of received bytes since the NetPeer was initialized
/// </summary>
public int ReceivedBytes { get { return m_receivedBytes; } }
/// <summary>
/// Gets the number of bytes allocated (and possibly garbage collected) for message storage
/// </summary>
public long StorageBytesAllocated { get { return m_bytesAllocated; } }
/// <summary>
/// Gets the number of bytes in the recycled pool
/// </summary>
public int BytesInRecyclePool { get { return m_peer.m_storagePoolBytes; } }
#if USE_RELEASE_STATISTICS
internal void PacketSent(int numBytes, int numMessages)
{
m_sentPackets++;
m_sentBytes += numBytes;
m_sentMessages += numMessages;
}
#else
[Conditional("DEBUG")]
internal void PacketSent(int numBytes, int numMessages)
{
m_sentPackets++;
m_sentBytes += numBytes;
m_sentMessages += numMessages;
}
#endif
#if USE_RELEASE_STATISTICS
internal void PacketReceived(int numBytes, int numMessages)
{
m_receivedPackets++;
m_receivedBytes += numBytes;
m_receivedMessages += numMessages;
}
#else
[Conditional("DEBUG")]
internal void PacketReceived(int numBytes, int numMessages)
{
m_receivedPackets++;
m_receivedBytes += numBytes;
m_receivedMessages += numMessages;
}
#endif
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
StringBuilder bdr = new StringBuilder();
bdr.AppendLine(m_peer.ConnectionsCount.ToString() + " connections");
#if DEBUG || USE_RELEASE_STATISTICS
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages in " + m_receivedPackets + " packets");
#else
bdr.AppendLine("Sent (n/a) bytes in (n/a) messages in (n/a) packets");
bdr.AppendLine("Received (n/a) bytes in (n/a) messages in (n/a) packets");
#endif
bdr.AppendLine("Storage allocated " + m_bytesAllocated + " bytes");
bdr.AppendLine("Recycled pool " + m_peer.m_storagePoolBytes + " bytes");
return bdr.ToString();
}
}
}

View File

@@ -1,49 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
namespace Lidgren.Network
{
/// <summary>
/// Status for a NetPeer instance
/// </summary>
public enum NetPeerStatus
{
/// <summary>
/// NetPeer is not running; socket is not bound
/// </summary>
NotRunning = 0,
/// <summary>
/// NetPeer is in the process of starting up
/// </summary>
Starting = 1,
/// <summary>
/// NetPeer is bound to socket and listening for packets
/// </summary>
Running = 2,
/// <summary>
/// Shutdown has been requested and will be executed shortly
/// </summary>
ShutdownRequested = 3,
}
}

View File

@@ -1,283 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
// @TODO: examine performance characteristics of using SpinLock when using .Net 4.0
namespace Lidgren.Network
{
/// <summary>
/// Thread safe (blocking) expanding queue with TryDequeue() and EnqueueFirst()
/// </summary>
[DebuggerDisplay("Count={Count} Capacity={Capacity}")]
public sealed class NetQueue<T>
{
// Example:
// m_capacity = 8
// m_size = 6
// m_head = 4
//
// [0] item
// [1] item (tail = ((head + size - 1) % capacity)
// [2]
// [3]
// [4] item (head)
// [5] item
// [6] item
// [7] item
//
private T[] m_items;
private readonly object m_lock;
private int m_size;
private int m_head;
/// <summary>
/// Gets the number of items in the queue
/// </summary>
public int Count { get { return m_size; } }
/// <summary>
/// Gets the current capacity for the queue
/// </summary>
public int Capacity { get { return m_items.Length; } }
/// <summary>
/// NetQueue constructor
/// </summary>
public NetQueue(int initialCapacity)
{
m_lock = new object();
m_items = new T[initialCapacity];
}
/// <summary>
/// Adds an item last/tail of the queue
/// </summary>
public void Enqueue(T item)
{
lock (m_lock)
{
if (m_size == m_items.Length)
SetCapacity(m_items.Length + 8);
int slot = (m_head + m_size) % m_items.Length;
m_items[slot] = item;
m_size++;
}
}
/// <summary>
/// Adds an item last/tail of the queue
/// </summary>
public void Enqueue(IEnumerable<T> items)
{
lock (m_lock)
{
foreach (var item in items)
{
if (m_size == m_items.Length)
SetCapacity(m_items.Length + 8); // @TODO move this out of loop
int slot = (m_head + m_size) % m_items.Length;
m_items[slot] = item;
m_size++;
}
}
}
/// <summary>
/// Places an item first, at the head of the queue
/// </summary>
public void EnqueueFirst(T item)
{
lock (m_lock)
{
if (m_size >= m_items.Length)
SetCapacity(m_items.Length + 8);
m_head--;
if (m_head < 0)
m_head = m_items.Length - 1;
m_items[m_head] = item;
m_size++;
}
}
// must be called from within a lock(m_lock) !
private void SetCapacity(int newCapacity)
{
if (m_size == 0)
{
if (m_size == 0)
{
m_items = new T[newCapacity];
m_head = 0;
return;
}
}
T[] newItems = new T[newCapacity];
if (m_head + m_size - 1 < m_items.Length)
{
Array.Copy(m_items, m_head, newItems, 0, m_size);
}
else
{
Array.Copy(m_items, m_head, newItems, 0, m_items.Length - m_head);
Array.Copy(m_items, 0, newItems, m_items.Length - m_head, (m_size - (m_items.Length - m_head)));
}
m_items = newItems;
m_head = 0;
}
/// <summary>
/// Gets an item from the head of the queue, or returns default(T) if empty
/// </summary>
public bool TryDequeue(out T item)
{
if (m_size == 0)
{
item = default(T);
return false;
}
lock (m_lock)
{
if (m_size == 0)
{
item = default(T);
return false;
}
item = m_items[m_head];
m_items[m_head] = default(T);
m_head = (m_head + 1) % m_items.Length;
m_size--;
return true;
}
}
/// <summary>
/// Gets an item from the head of the queue, or returns default(T) if empty
/// </summary>
public int TryDrain(IList<T> addTo)
{
if (m_size == 0)
return 0;
lock (m_lock)
{
int added = m_size;
while (m_size > 0)
{
var item = m_items[m_head];
addTo.Add(item);
m_items[m_head] = default(T);
m_head = (m_head + 1) % m_items.Length;
m_size--;
}
return added;
}
}
/// <summary>
/// Returns default(T) if queue is empty
/// </summary>
public T TryPeek(int offset)
{
if (m_size == 0)
return default(T);
lock (m_lock)
{
if (m_size == 0)
return default(T);
return m_items[(m_head + offset) % m_items.Length];
}
}
/// <summary>
/// Determines whether an item is in the queue
/// </summary>
public bool Contains(T item)
{
lock (m_lock)
{
int ptr = m_head;
for (int i = 0; i < m_size; i++)
{
if (m_items[ptr] == null)
{
if (item == null)
return true;
}
else
{
if (m_items[ptr].Equals(item))
return true;
}
ptr = (ptr + 1) % m_items.Length;
}
}
return false;
}
/// <summary>
/// Copies the queue items to a new array
/// </summary>
public T[] ToArray()
{
lock (m_lock)
{
T[] retval = new T[m_size];
int ptr = m_head;
for (int i = 0; i < m_size; i++)
{
retval[i] = m_items[ptr++];
if (ptr >= m_items.Length)
ptr = 0;
}
return retval;
}
}
/// <summary>
/// Removes all objects from the queue
/// </summary>
public void Clear()
{
lock (m_lock)
{
for (int i = 0; i < m_items.Length; i++)
m_items[i] = default(T);
m_head = 0;
m_size = 0;
}
}
}
}

View File

@@ -1,333 +0,0 @@
using System;
namespace Lidgren.Network
{
/// <summary>
/// A fast random number generator for .NET
/// Colin Green, January 2005
/// </summary>
/// September 4th 2005
/// Added NextBytesUnsafe() - commented out by default.
/// Fixed bug in Reinitialise() - y,z and w variables were not being reset.
///
/// Key points:
/// 1) Based on a simple and fast xor-shift pseudo random number generator (RNG) specified in:
/// Marsaglia, George. (2003). Xorshift RNGs.
/// http://www.jstatsoft.org/v08/i14/xorshift.pdf
///
/// This particular implementation of xorshift has a period of 2^128-1. See the above paper to see
/// how this can be easily extened if you need a longer period. At the time of writing I could find no
/// information on the period of System.Random for comparison.
///
/// 2) Faster than System.Random. Up to 8x faster, depending on which methods are called.
///
/// 3) Direct replacement for System.Random. This class implements all of the methods that System.Random
/// does plus some additional methods. The like named methods are functionally equivalent.
///
/// 4) Allows fast re-initialisation with a seed, unlike System.Random which accepts a seed at construction
/// time which then executes a relatively expensive initialisation routine. This provides a vast speed improvement
/// if you need to reset the pseudo-random number sequence many times, e.g. if you want to re-generate the same
/// sequence many times. An alternative might be to cache random numbers in an array, but that approach is limited
/// by memory capacity and the fact that you may also want a large number of different sequences cached. Each sequence
/// can each be represented by a single seed value (int) when using FastRandom.
///
/// Notes.
/// A further performance improvement can be obtained by declaring local variables as static, thus avoiding
/// re-allocation of variables on each call. However care should be taken if multiple instances of
/// FastRandom are in use or if being used in a multi-threaded environment.
public class NetRandom
{
/// <summary>
/// Gets a global NetRandom instance
/// </summary>
public static readonly NetRandom Instance = new NetRandom();
// The +1 ensures NextDouble doesn't generate 1.0
const double REAL_UNIT_INT = 1.0 / ((double)int.MaxValue + 1.0);
const double REAL_UNIT_UINT = 1.0 / ((double)uint.MaxValue + 1.0);
const uint Y = 842502087, Z = 3579807591, W = 273326509;
private static int s_extraSeed = 42;
uint x, y, z, w;
#region Constructors
/// <summary>
/// Initialises a new instance using time dependent seed.
/// </summary>
public NetRandom()
{
// Initialise using the system tick count.
Reinitialise(GetSeed(this));
}
/// <summary>
/// Initialises a new instance using an int value as seed.
/// This constructor signature is provided to maintain compatibility with
/// System.Random
/// </summary>
public NetRandom(int seed)
{
Reinitialise(seed);
}
/// <summary>
/// Create a semi-random seed based on an object
/// </summary>
public int GetSeed(object forObject)
{
// mix some semi-random properties
int seed = (int)Environment.TickCount;
seed ^= forObject.GetHashCode();
int extraSeed = System.Threading.Interlocked.Increment(ref s_extraSeed);
return seed + extraSeed;
}
#endregion
#region Public Methods [Reinitialisation]
/// <summary>
/// Reinitialises using an int value as a seed.
/// </summary>
/// <param name="seed"></param>
public void Reinitialise(int seed)
{
// The only stipulation stated for the xorshift RNG is that at least one of
// the seeds x,y,z,w is non-zero. We fulfill that requirement by only allowing
// resetting of the x seed
x = (uint)seed;
y = Y;
z = Z;
w = W;
}
#endregion
#region Public Methods [System.Random functionally equivalent methods]
/// <summary>
/// Generates a random int over the range 0 to int.MaxValue-1.
/// MaxValue is not generated in order to remain functionally equivalent to System.Random.Next().
/// This does slightly eat into some of the performance gain over System.Random, but not much.
/// For better performance see:
///
/// Call NextInt() for an int over the range 0 to int.MaxValue.
///
/// Call NextUInt() and cast the result to an int to generate an int over the full Int32 value range
/// including negative values.
/// </summary>
/// <returns></returns>
public int Next()
{
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
// Handle the special case where the value int.MaxValue is generated. This is outside of
// the range of permitted values, so we therefore call Next() to try again.
uint rtn = w & 0x7FFFFFFF;
if (rtn == 0x7FFFFFFF)
return Next();
return (int)rtn;
}
/// <summary>
/// Generates a random int over the range 0 to upperBound-1, and not including upperBound.
/// </summary>
/// <param name="upperBound"></param>
/// <returns></returns>
public int Next(int upperBound)
{
if (upperBound < 0)
throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=0");
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
// The explicit int cast before the first multiplication gives better performance.
// See comments in NextDouble.
return (int)((REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * upperBound);
}
/// <summary>
/// Generates a random int over the range lowerBound to upperBound-1, and not including upperBound.
/// upperBound must be >= lowerBound. lowerBound may be negative.
/// </summary>
/// <param name="lowerBound"></param>
/// <param name="upperBound"></param>
/// <returns></returns>
public int Next(int lowerBound, int upperBound)
{
if (lowerBound > upperBound)
throw new ArgumentOutOfRangeException("upperBound", upperBound, "upperBound must be >=lowerBound");
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
// The explicit int cast before the first multiplication gives better performance.
// See comments in NextDouble.
int range = upperBound - lowerBound;
if (range < 0)
{ // If range is <0 then an overflow has occured and must resort to using long integer arithmetic instead (slower).
// We also must use all 32 bits of precision, instead of the normal 31, which again is slower.
return lowerBound + (int)((REAL_UNIT_UINT * (double)(w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))) * (double)((long)upperBound - (long)lowerBound));
}
// 31 bits of precision will suffice if range<=int.MaxValue. This allows us to cast to an int and gain
// a little more performance.
return lowerBound + (int)((REAL_UNIT_INT * (double)(int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))))) * (double)range);
}
/// <summary>
/// Generates a random double. Values returned are from 0.0 up to but not including 1.0.
/// </summary>
/// <returns></returns>
public double NextDouble()
{
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
// Here we can gain a 2x speed improvement by generating a value that can be cast to
// an int instead of the more easily available uint. If we then explicitly cast to an
// int the compiler will then cast the int to a double to perform the multiplication,
// this final cast is a lot faster than casting from a uint to a double. The extra cast
// to an int is very fast (the allocated bits remain the same) and so the overall effect
// of the extra cast is a significant performance improvement.
//
// Also note that the loss of one bit of precision is equivalent to what occurs within
// System.Random.
return (REAL_UNIT_INT * (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)))));
}
/// <summary>
/// Generates a random single. Values returned are from 0.0 up to but not including 1.0.
/// </summary>
public float NextSingle()
{
return (float)NextDouble();
}
/// <summary>
/// Fills the provided byte array with random bytes.
/// This method is functionally equivalent to System.Random.NextBytes().
/// </summary>
/// <param name="buffer"></param>
public void NextBytes(byte[] buffer)
{
// Fill up the bulk of the buffer in chunks of 4 bytes at a time.
uint x = this.x, y = this.y, z = this.z, w = this.w;
int i = 0;
uint t;
for (int bound = buffer.Length - 3; i < bound; )
{
// Generate 4 bytes.
// Increased performance is achieved by generating 4 random bytes per loop.
// Also note that no mask needs to be applied to zero out the higher order bytes before
// casting because the cast ignores thos bytes. Thanks to Stefan Troschütz for pointing this out.
t = (x ^ (x << 11));
x = y; y = z; z = w;
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
buffer[i++] = (byte)w;
buffer[i++] = (byte)(w >> 8);
buffer[i++] = (byte)(w >> 16);
buffer[i++] = (byte)(w >> 24);
}
// Fill up any remaining bytes in the buffer.
if (i < buffer.Length)
{
// Generate 4 bytes.
t = (x ^ (x << 11));
x = y; y = z; z = w;
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
buffer[i++] = (byte)w;
if (i < buffer.Length)
{
buffer[i++] = (byte)(w >> 8);
if (i < buffer.Length)
{
buffer[i++] = (byte)(w >> 16);
if (i < buffer.Length)
{
buffer[i] = (byte)(w >> 24);
}
}
}
}
this.x = x; this.y = y; this.z = z; this.w = w;
}
#endregion
#region Public Methods [Methods not present on System.Random]
/// <summary>
/// Generates a uint. Values returned are over the full range of a uint,
/// uint.MinValue to uint.MaxValue, inclusive.
///
/// This is the fastest method for generating a single random number because the underlying
/// random number generator algorithm generates 32 random bits that can be cast directly to
/// a uint.
/// </summary>
[CLSCompliant(false)]
public uint NextUInt()
{
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)));
}
/// <summary>
/// Generates a random int over the range 0 to int.MaxValue, inclusive.
/// This method differs from Next() only in that the range is 0 to int.MaxValue
/// and not 0 to int.MaxValue-1.
///
/// The slight difference in range means this method is slightly faster than Next()
/// but is not functionally equivalent to System.Random.Next().
/// </summary>
/// <returns></returns>
public int NextInt()
{
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
return (int)(0x7FFFFFFF & (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))));
}
// Buffer 32 bits in bitBuffer, return 1 at a time, keep track of how many have been returned
// with bitBufferIdx.
uint bitBuffer;
uint bitMask = 1;
/// <summary>
/// Generates a single random bit.
/// This method's performance is improved by generating 32 bits in one operation and storing them
/// ready for future calls.
/// </summary>
/// <returns></returns>
public bool NextBool()
{
if (bitMask == 1)
{
// Generate 32 more bits.
uint t = (x ^ (x << 11));
x = y; y = z; z = w;
bitBuffer = w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
// Reset the bitMask that tells us which bit to read next.
bitMask = 0x80000000;
return (bitBuffer & bitMask) == 0;
}
return (bitBuffer & (bitMask >>= 1)) == 0;
}
#endregion
}
}

View File

@@ -1,18 +0,0 @@
using System;
namespace Lidgren.Network
{
internal abstract class NetReceiverChannelBase
{
internal NetPeer m_peer;
internal NetConnection m_connection;
public NetReceiverChannelBase(NetConnection connection)
{
m_connection = connection;
m_peer = connection.m_peer;
}
internal abstract void ReceiveMessage(NetIncomingMessage msg);
}
}

View File

@@ -1,80 +0,0 @@
using System;
namespace Lidgren.Network
{
internal sealed class NetReliableOrderedReceiver : NetReceiverChannelBase
{
private int m_windowStart;
private int m_windowSize;
private NetBitVector m_earlyReceived;
internal NetIncomingMessage[] m_withheldMessages;
public NetReliableOrderedReceiver(NetConnection connection, int windowSize)
: base(connection)
{
m_windowSize = windowSize;
m_withheldMessages = new NetIncomingMessage[windowSize];
m_earlyReceived = new NetBitVector(windowSize);
}
private void AdvanceWindow()
{
m_earlyReceived.Set(m_windowStart % m_windowSize, false);
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
}
internal override void ReceiveMessage(NetIncomingMessage message)
{
int relate = NetUtility.RelativeSequenceNumber(message.m_sequenceNumber, m_windowStart);
// ack no matter what
m_connection.QueueAck(message.m_receivedMessageType, message.m_sequenceNumber);
if (relate == 0)
{
AdvanceWindow();
m_peer.ReleaseMessage(message);
// release withheld messages
int nextSeqNr = (message.m_sequenceNumber + 1) % NetConstants.NumSequenceNumbers;
while (m_earlyReceived[nextSeqNr % m_windowSize])
{
message = m_withheldMessages[nextSeqNr % m_windowSize];
NetException.Assert(message != null);
// remove it from withheld messages
m_withheldMessages[nextSeqNr % m_windowSize] = null;
m_peer.LogVerbose("Releasing withheld message #" + message);
m_peer.ReleaseMessage(message);
AdvanceWindow();
nextSeqNr++;
}
return;
}
if (relate < 0)
{
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
// duplicate
return;
}
// relate > 0 = early message
if (relate > m_windowSize)
{
// too early message!
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
return;
}
m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true);
m_peer.LogVerbose("Received " + message + " WITHHOLDING, waiting for " + m_windowStart);
m_withheldMessages[message.m_sequenceNumber % m_windowSize] = message;
}
}
}

View File

@@ -1,243 +0,0 @@
using System;
using System.Threading;
namespace Lidgren.Network
{
/// <summary>
/// Sender part of Selective repeat ARQ for a particular NetChannel
/// </summary>
internal sealed class NetReliableSenderChannel : NetSenderChannelBase
{
private NetConnection m_connection;
private int m_windowStart;
private int m_windowSize;
private int m_sendStart;
private NetBitVector m_receivedAcks;
internal NetStoredReliableMessage[] m_storedMessages;
internal float m_resendDelay;
internal override int WindowSize { get { return m_windowSize; } }
internal NetReliableSenderChannel(NetConnection connection, int windowSize)
{
m_connection = connection;
m_windowSize = windowSize;
m_windowStart = 0;
m_sendStart = 0;
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
m_storedMessages = new NetStoredReliableMessage[m_windowSize];
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
m_resendDelay = m_connection.GetResendDelay();
}
internal override int GetAllowedSends()
{
int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers;
NetException.Assert(retval >= 0 && retval <= m_windowSize);
return retval;
}
internal override void Reset()
{
m_receivedAcks.Clear();
for (int i = 0; i < m_storedMessages.Length; i++)
m_storedMessages[i].Reset();
m_queuedSends.Clear();
m_windowStart = 0;
m_sendStart = 0;
}
internal override NetSendResult Enqueue(NetOutgoingMessage message)
{
m_queuedSends.Enqueue(message);
int queueLen = m_queuedSends.Count;
int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers;
if (queueLen <= left)
return NetSendResult.Sent;
return NetSendResult.Queued;
}
// call this regularely
internal override void SendQueuedMessages(float now)
{
//
// resends
//
for (int i = 0; i < m_storedMessages.Length; i++)
{
NetOutgoingMessage om = m_storedMessages[i].Message;
if (om == null)
continue;
float t = m_storedMessages[i].LastSent;
if (t > 0 && (now - t) > m_resendDelay)
{
// deduce sequence number
int startSlot = m_windowStart % m_windowSize;
int seqNr = m_windowStart;
while (startSlot != i)
{
startSlot--;
if (startSlot < 0)
startSlot = m_windowSize - 1;
seqNr--;
}
m_connection.m_statistics.MessageResent(MessageResendReason.Delay);
m_connection.QueueSendMessage(om, seqNr);
m_storedMessages[i].LastSent = now;
m_storedMessages[i].NumSent++;
}
}
int num = GetAllowedSends();
if (num < 1)
return;
// queued sends
while (m_queuedSends.Count > 0 && num > 0)
{
NetOutgoingMessage om;
if (m_queuedSends.TryDequeue(out om))
ExecuteSend(now, om);
num--;
NetException.Assert(num == GetAllowedSends());
}
}
private void ExecuteSend(float now, NetOutgoingMessage message)
{
int seqNr = m_sendStart;
m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers;
m_connection.QueueSendMessage(message, seqNr);
int storeIndex = seqNr % m_windowSize;
NetException.Assert(m_storedMessages[storeIndex].Message == null);
m_storedMessages[storeIndex].NumSent++;
m_storedMessages[storeIndex].Message = message;
m_storedMessages[storeIndex].LastSent = now;
return;
}
private void DestoreMessage(int storeIndex)
{
NetOutgoingMessage storedMessage = m_storedMessages[storeIndex].Message;
#if DEBUG
if (storedMessage == null)
throw new NetException("m_storedMessages[" + storeIndex + "].Message is null; sent " + m_storedMessages[storeIndex].NumSent + " times, last time " + (NetTime.Now - m_storedMessages[storeIndex].LastSent) + " seconds ago");
#else
if (storedMessage != null)
{
#endif
Interlocked.Decrement(ref storedMessage.m_recyclingCount);
if (storedMessage.m_recyclingCount <= 0)
m_connection.m_peer.Recycle(storedMessage);
#if !DEBUG
}
#endif
m_storedMessages[storeIndex] = new NetStoredReliableMessage();
}
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
// seqNr is the actual nr received
internal override void ReceiveAcknowledge(float now, int seqNr)
{
// late (dupe), on time or early ack?
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
if (relate < 0)
return; // late/duplicate ack
if (relate == 0)
{
// ack arrived right on time
NetException.Assert(seqNr == m_windowStart);
m_receivedAcks[m_windowStart] = false;
DestoreMessage(m_windowStart % m_windowSize);
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
// advance window if we already have early acks
while (m_receivedAcks.Get(m_windowStart))
{
m_receivedAcks[m_windowStart] = false;
DestoreMessage(m_windowStart % m_windowSize);
NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
}
return;
}
//
// early ack... (if it has been sent!)
//
// If it has been sent either the m_windowStart message was lost
// ... or the ack for that message was lost
//
int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart);
if (sendRelate <= 0)
{
// yes, we've sent this message - it's an early (but valid) ack
if (m_receivedAcks[seqNr])
{
// we've already destored/been acked for this message
}
else
{
m_receivedAcks[seqNr] = true;
}
}
else if (sendRelate > 0)
{
// uh... we haven't sent this message yet? Weird, dupe or error...
NetException.Assert(false, "Got ack for message not yet sent?");
return;
}
// Ok, lets resend all missing acks
int rnr = seqNr;
do
{
rnr--;
if (rnr < 0)
rnr = NetConstants.NumSequenceNumbers - 1;
if (!m_receivedAcks[rnr])
{
int slot = rnr % m_windowSize;
NetException.Assert(m_storedMessages[slot].Message != null);
if (m_storedMessages[slot].NumSent == 1)
{
// just sent once; resend immediately since we found gap in ack sequence
NetOutgoingMessage rmsg = m_storedMessages[slot].Message;
if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35f))
{
// already resent recently
}
else
{
m_storedMessages[slot].LastSent = now;
m_storedMessages[slot].NumSent++;
m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence);
m_connection.QueueSendMessage(rmsg, rnr);
}
}
}
} while (rnr != m_windowStart);
}
}
}

View File

@@ -1,57 +0,0 @@
using System;
namespace Lidgren.Network
{
internal sealed class NetReliableSequencedReceiver : NetReceiverChannelBase
{
private int m_windowStart;
private int m_windowSize;
public NetReliableSequencedReceiver(NetConnection connection, int windowSize)
: base(connection)
{
m_windowSize = windowSize;
}
private void AdvanceWindow()
{
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
}
internal override void ReceiveMessage(NetIncomingMessage message)
{
int nr = message.m_sequenceNumber;
int relate = NetUtility.RelativeSequenceNumber(nr, m_windowStart);
// ack no matter what
m_connection.QueueAck(message.m_receivedMessageType, nr);
if (relate == 0)
{
AdvanceWindow();
m_peer.ReleaseMessage(message);
return;
}
if (relate < 0)
{
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING LATE or DUPE");
return;
}
// relate > 0 = early message
if (relate > m_windowSize)
{
// too early message!
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
return;
}
// ok
m_windowStart = (m_windowStart + relate) % NetConstants.NumSequenceNumbers;
m_peer.ReleaseMessage(message);
return;
}
}
}

View File

@@ -1,68 +0,0 @@
using System;
namespace Lidgren.Network
{
internal sealed class NetReliableUnorderedReceiver : NetReceiverChannelBase
{
private int m_windowStart;
private int m_windowSize;
private NetBitVector m_earlyReceived;
public NetReliableUnorderedReceiver(NetConnection connection, int windowSize)
: base(connection)
{
m_windowSize = windowSize;
m_earlyReceived = new NetBitVector(windowSize);
}
private void AdvanceWindow()
{
m_earlyReceived.Set(m_windowStart % m_windowSize, false);
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
}
internal override void ReceiveMessage(NetIncomingMessage message)
{
int relate = NetUtility.RelativeSequenceNumber(message.m_sequenceNumber, m_windowStart);
// ack no matter what
m_connection.QueueAck(message.m_receivedMessageType, message.m_sequenceNumber);
if (relate == 0)
{
AdvanceWindow();
m_peer.ReleaseMessage(message);
// release withheld messages
int nextSeqNr = (message.m_sequenceNumber + 1) % NetConstants.NumSequenceNumbers;
while (m_earlyReceived[nextSeqNr % m_windowSize])
{
AdvanceWindow();
nextSeqNr++;
}
return;
}
if (relate < 0)
{
// duplicate
m_peer.LogVerbose("Received message #" + message.m_sequenceNumber + " DROPPING DUPLICATE");
return;
}
// relate > 0 = early message
if (relate > m_windowSize)
{
// too early message!
m_peer.LogDebug("Received " + message + " TOO EARLY! Expected " + m_windowStart);
return;
}
m_earlyReceived.Set(message.m_sequenceNumber % m_windowSize, true);
m_peer.ReleaseMessage(message);
}
}
}

View File

@@ -1,203 +0,0 @@
#define USE_SHA256
using System;
using System.Security.Cryptography;
using System.Text;
namespace Lidgren.Network
{
/// <summary>
/// Helper methods for implementing SRP authentication
/// </summary>
public static class NetSRP
{
private static readonly NetBigInteger N = new NetBigInteger("0115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16);
private static readonly NetBigInteger g = NetBigInteger.Two;
private static readonly NetBigInteger k = ComputeMultiplier();
private static HashAlgorithm GetHashAlgorithm()
{
#if USE_SHA256
// this does not seem to work as of yet
return SHA256.Create();
#else
return SHA1.Create();
#endif
}
/// <summary>
/// Compute multiplier (k)
/// </summary>
private static NetBigInteger ComputeMultiplier()
{
string one = NetUtility.ToHexString(N.ToByteArrayUnsigned());
string two = NetUtility.ToHexString(g.ToByteArrayUnsigned());
string ccstr = one + two.PadLeft(one.Length, '0');
byte[] cc = NetUtility.ToByteArray(ccstr);
var sha = GetHashAlgorithm();
var ccHashed = sha.ComputeHash(cc);
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16);
}
/// <summary>
/// Create 16 bytes of random salt
/// </summary>
public static byte[] CreateRandomSalt()
{
byte[] retval = new byte[16];
NetRandom.Instance.NextBytes(retval);
return retval;
}
/// <summary>
/// Create 32 bytes of random ephemeral value
/// </summary>
public static byte[] CreateRandomEphemeral()
{
byte[] retval = new byte[32];
NetRandom.Instance.NextBytes(retval);
return retval;
}
/// <summary>
/// Computer private key (x)
/// </summary>
public static byte[] ComputePrivateKey(string username, string password, byte[] salt)
{
var sha = GetHashAlgorithm();
byte[] tmp = Encoding.UTF8.GetBytes(username + ":" + password);
byte[] innerHash = sha.ComputeHash(tmp);
byte[] total = new byte[innerHash.Length + salt.Length];
Buffer.BlockCopy(salt, 0, total, 0, salt.Length);
Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length);
return new NetBigInteger(NetUtility.ToHexString(sha.ComputeHash(total)), 16).ToByteArrayUnsigned();
}
/// <summary>
/// Creates a verifier that the server can later use to authenticate users later on (v)
/// </summary>
public static byte[] ComputeServerVerifier(byte[] privateKey)
{
NetBigInteger x = new NetBigInteger(NetUtility.ToHexString(privateKey), 16);
// Verifier (v) = g^x (mod N)
var serverVerifier = g.ModPow(x, N);
return serverVerifier.ToByteArrayUnsigned();
}
/// <summary>
/// SHA hash data
/// </summary>
public static byte[] Hash(byte[] data)
{
var sha = GetHashAlgorithm();
return sha.ComputeHash(data);
}
/// <summary>
/// Compute client public ephemeral value (A)
/// </summary>
public static byte[] ComputeClientEphemeral(byte[] clientPrivateEphemeral) // a
{
// A= g^a (mod N)
NetBigInteger a = new NetBigInteger(NetUtility.ToHexString(clientPrivateEphemeral), 16);
NetBigInteger retval = g.ModPow(a, N);
return retval.ToByteArrayUnsigned();
}
/// <summary>
/// Compute server ephemeral value (B)
/// </summary>
public static byte[] ComputeServerEphemeral(byte[] serverPrivateEphemeral, byte[] verifier) // b
{
var b = new NetBigInteger(NetUtility.ToHexString(serverPrivateEphemeral), 16);
var v = new NetBigInteger(NetUtility.ToHexString(verifier), 16);
// B = kv + g^b (mod N)
var bb = g.ModPow(b, N);
var kv = v.Multiply(k);
var B = (kv.Add(bb)).Mod(N);
return B.ToByteArrayUnsigned();
}
/// <summary>
/// Compute intermediate value (u)
/// </summary>
public static byte[] ComputeU(byte[] clientPublicEphemeral, byte[] serverPublicEphemeral)
{
// u = SHA-1(A || B)
string one = NetUtility.ToHexString(clientPublicEphemeral);
string two = NetUtility.ToHexString(serverPublicEphemeral);
int len = 66;
string ccstr = one.PadLeft(len, '0') + two.PadLeft(len, '0');
byte[] cc = NetUtility.ToByteArray(ccstr);
var sha = GetHashAlgorithm();
var ccHashed = sha.ComputeHash(cc);
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16).ToByteArrayUnsigned();
}
/// <summary>
/// Computes the server session value
/// </summary>
public static byte[] ComputeServerSessionValue(byte[] clientPublicEphemeral, byte[] verifier, byte[] udata, byte[] serverPrivateEphemeral)
{
// S = (Av^u) ^ b (mod N)
var A = new NetBigInteger(NetUtility.ToHexString(clientPublicEphemeral), 16);
var v = new NetBigInteger(NetUtility.ToHexString(verifier), 16);
var u = new NetBigInteger(NetUtility.ToHexString(udata), 16);
var b = new NetBigInteger(NetUtility.ToHexString(serverPrivateEphemeral), 16);
NetBigInteger retval = v.ModPow(u, N).Multiply(A).Mod(N).ModPow(b, N).Mod(N);
return retval.ToByteArrayUnsigned();
}
/// <summary>
/// Computes the client session value
/// </summary>
public static byte[] ComputeClientSessionValue(byte[] serverPublicEphemeral, byte[] xdata, byte[] udata, byte[] clientPrivateEphemeral)
{
// (B - kg^x) ^ (a + ux) (mod N)
var B = new NetBigInteger(NetUtility.ToHexString(serverPublicEphemeral), 16);
var x = new NetBigInteger(NetUtility.ToHexString(xdata), 16);
var u = new NetBigInteger(NetUtility.ToHexString(udata), 16);
var a = new NetBigInteger(NetUtility.ToHexString(clientPrivateEphemeral), 16);
var bx = g.ModPow(x, N);
var btmp = B.Add(N.Multiply(k)).Subtract(bx.Multiply(k)).Mod(N);
return btmp.ModPow(x.Multiply(u).Add(a), N).ToByteArrayUnsigned();
}
/// <summary>
/// Create XTEA symmetrical encryption object from sessionValue
/// </summary>
public static NetXtea CreateEncryption(byte[] sessionValue)
{
var sha = GetHashAlgorithm();
var hash = sha.ComputeHash(sessionValue);
var key = new byte[16];
for(int i=0;i<16;i++)
{
key[i] = hash[i];
for (int j = 1; j < hash.Length / 16; j++)
key[i] ^= hash[i + (j * 16)];
}
return new NetXtea(key);
}
}
}

View File

@@ -1,30 +0,0 @@
using System;
namespace Lidgren.Network
{
/// <summary>
/// Result of a SendMessage call
/// </summary>
public enum NetSendResult
{
/// <summary>
/// Message failed to enqueue because there is no connection
/// </summary>
FailedNotConnected = 0,
/// <summary>
/// Message was immediately sent
/// </summary>
Sent = 1,
/// <summary>
/// Message was queued for delivery
/// </summary>
Queued = 2,
/// <summary>
/// Message was dropped immediately since too many message were queued
/// </summary>
Dropped = 3
}
}

View File

@@ -1,19 +0,0 @@
using System;
namespace Lidgren.Network
{
internal abstract class NetSenderChannelBase
{
// access this directly to queue things in this channel
internal NetQueue<NetOutgoingMessage> m_queuedSends;
internal abstract int WindowSize { get; }
internal abstract int GetAllowedSends();
internal abstract NetSendResult Enqueue(NetOutgoingMessage message);
internal abstract void SendQueuedMessages(float now);
internal abstract void Reset();
internal abstract void ReceiveAcknowledge(float now, int sequenceNumber);
}
}

View File

@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
namespace Lidgren.Network
{
/// <summary>
/// Specialized version of NetPeer used for "server" peers
/// </summary>
public class NetServer : NetPeer
{
/// <summary>
/// NetServer constructor
/// </summary>
public NetServer(NetPeerConfiguration config)
: base(config)
{
config.AcceptIncomingConnections = true;
}
/// <summary>
/// Send a message to all connections
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="method">How to deliver the message</param>
public void SendToAll(NetOutgoingMessage msg, NetDeliveryMethod method)
{
var all = this.Connections;
if (all.Count <= 0)
return;
SendMessage(msg, all, method, 0);
}
/// <summary>
/// Send a message to all connections except one
/// </summary>
/// <param name="msg">The message to send</param>
/// <param name="method">How to deliver the message</param>
/// <param name="except">Don't send to this particular connection</param>
/// <param name="sequenceChannel">Which sequence channel to use for the message</param>
public void SendToAll(NetOutgoingMessage msg, NetConnection except, NetDeliveryMethod method, int sequenceChannel)
{
var all = this.Connections;
if (all.Count <= 0)
return;
if (except == null)
{
SendMessage(msg, all, method, sequenceChannel);
return;
}
List<NetConnection> recipients = new List<NetConnection>(all.Count - 1);
foreach (var conn in all)
if (conn != except)
recipients.Add(conn);
if (recipients.Count > 0)
SendMessage(msg, recipients, method, sequenceChannel);
}
/// <summary>
/// Returns a string that represents this object
/// </summary>
public override string ToString()
{
return "[NetServer " + ConnectionsCount + " connections]";
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
namespace Lidgren.Network
{
internal struct NetStoredReliableMessage
{
public int NumSent;
public float LastSent;
public NetOutgoingMessage Message;
public void Reset()
{
NumSent = 0;
LastSent = 0;
Message = null;
}
}
}

View File

@@ -1,61 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define IS_STOPWATCH_AVAILABLE
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace Lidgren.Network
{
/// <summary>
/// Time service
/// </summary>
public static class NetTime
{
#if IS_STOPWATCH_AVAILABLE
private static readonly long s_timeInitialized = Stopwatch.GetTimestamp();
private static readonly double s_dInvFreq = 1.0 / (double)Stopwatch.Frequency;
/// <summary>
/// Get number of seconds since the application started
/// </summary>
public static double Now { get { return (double)(Stopwatch.GetTimestamp() - s_timeInitialized) * s_dInvFreq; } }
#else
private static readonly uint s_timeInitialized = (uint)Environment.TickCount;
/// <summary>
/// Get number of seconds since the application started
/// </summary>
public static double Now { get { return (double)((uint)Environment.TickCount - s_timeInitialized) / 1000.0; } }
#endif
/// <summary>
/// Given seconds it will output a human friendly readable string (milliseconds if less than 60 seconds)
/// </summary>
public static string ToReadable(double seconds)
{
if (seconds > 60)
return TimeSpan.FromSeconds(seconds).ToString();
return (seconds * 1000.0).ToString("N2") + " ms";
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Lidgren.Network
{
// replace with BCL 4.0 Tuple<> when appropriate
internal struct NetTuple<A, B>
{
public A Item1;
public B Item2;
public NetTuple(A item1, B item2)
{
Item1 = item1;
Item2 = item2;
}
}
}

View File

@@ -1,191 +0,0 @@
using System;
using System.IO;
using System.Xml;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Lidgren.Network
{
/// <summary>
/// UPnP support class
/// </summary>
public class NetUPnP
{
private const int c_discoveryTimeOutMillis = 1000;
private string m_serviceUrl;
private NetPeer m_peer;
private ManualResetEvent m_discoveryComplete = new ManualResetEvent(false);
/// <summary>
/// NetUPnP constructor
/// </summary>
public NetUPnP(NetPeer peer)
{
m_peer = peer;
}
internal void Discover(NetPeer peer)
{
string str =
"M-SEARCH * HTTP/1.1\r\n" +
"HOST: 239.255.255.250:1900\r\n" +
"ST:upnp:rootdevice\r\n" +
"MAN:\"ssdp:discover\"\r\n" +
"MX:3\r\n\r\n";
byte[] arr = System.Text.Encoding.UTF8.GetBytes(str);
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
peer.RawSend(arr, 0, arr.Length, new IPEndPoint(IPAddress.Broadcast, 1900));
peer.Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, false);
}
internal void ExtractServiceUrl(string resp)
{
#if !DEBUG
try
{
#endif
XmlDocument desc = new XmlDocument();
desc.Load(WebRequest.Create(resp).GetResponse().GetResponseStream());
XmlNamespaceManager nsMgr = new XmlNamespaceManager(desc.NameTable);
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
XmlNode typen = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr);
if (!typen.Value.Contains("InternetGatewayDevice"))
return;
XmlNode node = desc.SelectSingleNode("//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:WANIPConnection:1\"]/tns:controlURL/text()", nsMgr);
if (node == null)
return;
m_serviceUrl = CombineUrls(resp, node.Value);
m_peer.LogDebug("UPnP service ready");
m_discoveryComplete.Set();
#if !DEBUG
}
catch { return; }
#endif
}
private static string CombineUrls(string gatewayURL, string subURL)
{
// Is Control URL an absolute URL?
if ((subURL.Contains("http:")) || (subURL.Contains(".")))
return subURL;
gatewayURL = gatewayURL.Replace("http://", ""); // strip any protocol
int n = gatewayURL.IndexOf("/");
if (n != -1)
gatewayURL = gatewayURL.Substring(0, n); // Use first portion of URL
return "http://" + gatewayURL + subURL;
}
/// <summary>
/// Add a forwarding rule to the router using UPnP
/// </summary>
public bool ForwardPort(int port, string description)
{
if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis))
return false;
IPAddress mask;
var client = NetUtility.GetMyAddress(out mask);
if (client == null)
return false;
try
{
XmlDocument xdoc = SOAPRequest(m_serviceUrl,
"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + port.ToString() + "</NewExternalPort>" +
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
"<NewInternalPort>" + port.ToString() + "</NewInternalPort>" +
"<NewInternalClient>" + client.ToString() + "</NewInternalClient>" +
"<NewEnabled>1</NewEnabled>" +
"<NewPortMappingDescription>" + description + "</NewPortMappingDescription>" +
"<NewLeaseDuration>0</NewLeaseDuration>" +
"</u:AddPortMapping>",
"AddPortMapping");
m_peer.LogDebug("Sent UPnP port forward request");
System.Threading.Thread.Sleep(50);
}
catch (Exception ex)
{
m_peer.LogWarning("UPnP port forward failed: " + ex.Message);
return false;
}
return true;
}
/// <summary>
/// Delete a forwarding rule from the router using UPnP
/// </summary>
public bool DeleteForwardingRule(int port)
{
if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis))
return false;
try
{
XmlDocument xdoc = SOAPRequest(m_serviceUrl,
"<u:DeletePortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"<NewRemoteHost>" +
"</NewRemoteHost>" +
"<NewExternalPort>" + port + "</NewExternalPort>" +
"<NewProtocol>" + ProtocolType.Udp.ToString().ToUpper() + "</NewProtocol>" +
"</u:DeletePortMapping>", "DeletePortMapping");
return true;
}
catch (Exception ex)
{
m_peer.LogWarning("UPnP delete forwarding rule failed: " + ex.Message);
return false;
}
}
/// <summary>
/// Retrieve the extern ip using UPnP
/// </summary>
public IPAddress GetExternalIP()
{
if (m_serviceUrl == null && !m_discoveryComplete.WaitOne(c_discoveryTimeOutMillis))
return null;
try
{
XmlDocument xdoc = SOAPRequest(m_serviceUrl, "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
"</u:GetExternalIPAddress>", "GetExternalIPAddress");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0");
string IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value;
return IPAddress.Parse(IP);
}
catch (Exception ex)
{
m_peer.LogWarning("Failed to get external IP: " + ex.Message);
return null;
}
}
private XmlDocument SOAPRequest(string url, string soap, string function)
{
string req = "<?xml version=\"1.0\"?>" +
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
"<s:Body>" +
soap +
"</s:Body>" +
"</s:Envelope>";
WebRequest r = HttpWebRequest.Create(url);
r.Method = "POST";
byte[] b = System.Text.Encoding.UTF8.GetBytes(req);
r.Headers.Add("SOAPACTION", "\"urn:schemas-upnp-org:service:WANIPConnection:1#" + function + "\"");
r.ContentType = "text/xml; charset=\"utf-8\"";
r.ContentLength = b.Length;
r.GetRequestStream().Write(b, 0, b.Length);
XmlDocument resp = new XmlDocument();
WebResponse wres = r.GetResponse();
Stream ress = wres.GetResponseStream();
resp.Load(ress);
return resp;
}
}
}

View File

@@ -1,120 +0,0 @@
using System;
using System.Threading;
namespace Lidgren.Network
{
/// <summary>
/// Sender part of Selective repeat ARQ for a particular NetChannel
/// </summary>
internal sealed class NetUnreliableSenderChannel : NetSenderChannelBase
{
private NetConnection m_connection;
private int m_windowStart;
private int m_windowSize;
private int m_sendStart;
private NetBitVector m_receivedAcks;
internal override int WindowSize { get { return m_windowSize; } }
internal NetUnreliableSenderChannel(NetConnection connection, int windowSize)
{
m_connection = connection;
m_windowSize = windowSize;
m_windowStart = 0;
m_sendStart = 0;
m_receivedAcks = new NetBitVector(NetConstants.NumSequenceNumbers);
m_queuedSends = new NetQueue<NetOutgoingMessage>(8);
}
internal override int GetAllowedSends()
{
int retval = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % m_windowSize;
NetException.Assert(retval >= 0 && retval <= m_windowSize);
return retval;
}
internal override void Reset()
{
m_receivedAcks.Clear();
m_queuedSends.Clear();
m_windowStart = 0;
m_sendStart = 0;
}
internal override NetSendResult Enqueue(NetOutgoingMessage message)
{
int queueLen = m_queuedSends.Count + 1;
int left = m_windowSize - ((m_sendStart + NetConstants.NumSequenceNumbers) - m_windowStart) % NetConstants.NumSequenceNumbers;
if (queueLen > left)
return NetSendResult.Dropped;
m_queuedSends.Enqueue(message);
return NetSendResult.Sent;
}
// call this regularely
internal override void SendQueuedMessages(float now)
{
int num = GetAllowedSends();
if (num < 1)
return;
// queued sends
while (m_queuedSends.Count > 0 && num > 0)
{
NetOutgoingMessage om;
if (m_queuedSends.TryDequeue(out om))
ExecuteSend(now, om);
num--;
}
}
private void ExecuteSend(float now, NetOutgoingMessage message)
{
m_connection.m_peer.VerifyNetworkThread();
int seqNr = m_sendStart;
m_sendStart = (m_sendStart + 1) % NetConstants.NumSequenceNumbers;
m_connection.QueueSendMessage(message, seqNr);
Interlocked.Decrement(ref message.m_recyclingCount);
if (message.m_recyclingCount <= 0)
m_connection.m_peer.Recycle(message);
return;
}
// remoteWindowStart is remote expected sequence number; everything below this has arrived properly
// seqNr is the actual nr received
internal override void ReceiveAcknowledge(float now, int seqNr)
{
// late (dupe), on time or early ack?
int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart);
if (relate < 0)
return; // late/duplicate ack
if (relate == 0)
{
// ack arrived right on time
NetException.Assert(seqNr == m_windowStart);
m_receivedAcks[m_windowStart] = false;
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
return;
}
// Advance window to this position
m_receivedAcks[seqNr] = true;
while (m_windowStart != seqNr)
{
m_receivedAcks[m_windowStart] = false;
m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers;
}
}
}
}

View File

@@ -1,29 +0,0 @@
using System;
namespace Lidgren.Network
{
internal sealed class NetUnreliableSequencedReceiver : NetReceiverChannelBase
{
private int m_lastReceivedSequenceNumber;
public NetUnreliableSequencedReceiver(NetConnection connection)
: base(connection)
{
}
internal override void ReceiveMessage(NetIncomingMessage msg)
{
int nr = msg.m_sequenceNumber;
// ack no matter what
m_connection.QueueAck(msg.m_receivedMessageType, nr);
int relate = NetUtility.RelativeSequenceNumber(nr, m_lastReceivedSequenceNumber);
if (relate < 0)
return; // drop if late
m_lastReceivedSequenceNumber = nr;
m_peer.ReleaseMessage(msg);
}
}
}

View File

@@ -1,20 +0,0 @@
using System;
namespace Lidgren.Network
{
internal sealed class NetUnreliableUnorderedReceiver : NetReceiverChannelBase
{
public NetUnreliableUnorderedReceiver(NetConnection connection)
: base(connection)
{
}
internal override void ReceiveMessage(NetIncomingMessage msg)
{
// ack no matter what
m_connection.QueueAck(msg.m_receivedMessageType, msg.m_sequenceNumber);
m_peer.ReleaseMessage(msg);
}
}
}

View File

@@ -1,632 +0,0 @@
/* Copyright (c) 2010 Michael Lidgren
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if !__ANDROID__ && !IOS
#define IS_FULL_NET_AVAILABLE
#endif
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Lidgren.Network
{
/// <summary>
/// Utility methods
/// </summary>
public static class NetUtility
{
/// <summary>
/// Resolve endpoint callback
/// </summary>
public delegate void ResolveEndPointCallback(IPEndPoint endPoint);
/// <summary>
/// Resolve address callback
/// </summary>
public delegate void ResolveAddressCallback(IPAddress adr);
/// <summary>
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number (asynchronous version)
/// </summary>
public static void ResolveAsync(string ipOrHost, int port, ResolveEndPointCallback callback)
{
ResolveAsync(ipOrHost, delegate(IPAddress adr)
{
if (adr == null)
{
callback(null);
}
else
{
callback(new IPEndPoint(adr, port));
}
});
}
/// <summary>
/// Get IPv4 endpoint from notation (xxx.xxx.xxx.xxx) or hostname and port number
/// </summary>
public static IPEndPoint Resolve(string ipOrHost, int port)
{
IPAddress adr = Resolve(ipOrHost);
return new IPEndPoint(adr, port);
}
/// <summary>
/// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname (asynchronous version)
/// </summary>
public static void ResolveAsync(string ipOrHost, ResolveAddressCallback callback)
{
if (string.IsNullOrEmpty(ipOrHost))
throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
ipOrHost = ipOrHost.Trim();
IPAddress ipAddress = null;
if (IPAddress.TryParse(ipOrHost, out ipAddress))
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork
|| ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
callback(ipAddress);
return;
}
throw new ArgumentException("This method will not currently resolve other than ipv4 addresses");
}
// ok must be a host name
IPHostEntry entry;
try
{
Dns.BeginGetHostEntry(ipOrHost, delegate(IAsyncResult result)
{
try
{
entry = Dns.EndGetHostEntry(result);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.HostNotFound)
{
callback(null);
return;
}
else
{
throw;
}
}
if (entry == null)
{
callback(null);
return;
}
// check each entry for a valid IP address
IPAddress bestAddress = null;
foreach (IPAddress ipCurrent in entry.AddressList)
{
// Prefer IPv6 addresses.
if (ipCurrent.AddressFamily == AddressFamily.InterNetworkV6)
{
callback(ipCurrent);
return;
}
if (ipCurrent.AddressFamily == AddressFamily.InterNetwork)
{
bestAddress = ipCurrent;
}
}
callback(bestAddress);
}, null);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.HostNotFound)
{
callback(null);
}
else
{
throw;
}
}
}
public static async Task<IPAddress[]> ResolveAsync(string ipOrHost)
{
if (string.IsNullOrEmpty(ipOrHost))
throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
ipOrHost = ipOrHost.Trim();
if (IPAddress.TryParse(ipOrHost, out var ipAddress))
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork
|| ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
return new[] {ipAddress};
}
throw new ArgumentException("This method will not currently resolve other than IPv4 or IPv6 addresses");
}
try
{
var entry = await Dns.GetHostEntryAsync(ipOrHost);
return entry.AddressList;
}
catch (SocketException)
{
return null;
}
}
/// <summary>
/// Get IPv4 address from notation (xxx.xxx.xxx.xxx) or hostname
/// </summary>
public static IPAddress Resolve(string ipOrHost)
{
if (string.IsNullOrEmpty(ipOrHost))
throw new ArgumentException("Supplied string must not be empty", "ipOrHost");
ipOrHost = ipOrHost.Trim();
IPAddress ipAddress = null;
if (IPAddress.TryParse(ipOrHost, out ipAddress))
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork
|| ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
return ipAddress;
throw new ArgumentException("This method will not currently resolve other than ipv4 addresses");
}
// ok must be a host name
IPHostEntry entry;
try
{
entry = Dns.GetHostEntry(ipOrHost);
if (entry == null)
return null;
// check each entry for a valid IP address
IPAddress bestAddress = null;
foreach (IPAddress ipCurrent in entry.AddressList)
{
if (ipCurrent.AddressFamily == AddressFamily.InterNetworkV6)
{
return ipCurrent;
}
// Prefer IPv6 addresses.
if (ipCurrent.AddressFamily == AddressFamily.InterNetwork)
{
bestAddress = ipCurrent;
}
}
return bestAddress;
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.HostNotFound)
{
return null;
}
else
{
throw;
}
}
}
#if IS_FULL_NET_AVAILABLE
private static NetworkInterface GetNetworkInterface()
{
IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();
if (computerProperties == null)
return null;
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
if (nics == null || nics.Length < 1)
return null;
NetworkInterface best = null;
foreach (NetworkInterface adapter in nics)
{
if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback || adapter.NetworkInterfaceType == NetworkInterfaceType.Unknown)
continue;
if (!adapter.Supports(NetworkInterfaceComponent.IPv4))
continue;
if (best == null)
best = adapter;
if (adapter.OperationalStatus != OperationalStatus.Up)
continue;
// A computer could have several adapters (more than one network card)
// here but just return the first one for now...
return adapter;
}
return best;
}
/// <summary>
/// Returns the physical (MAC) address for the first usable network interface
/// </summary>
public static PhysicalAddress GetMacAddress()
{
NetworkInterface ni = GetNetworkInterface();
if (ni == null)
return null;
return ni.GetPhysicalAddress();
}
#endif
/// <summary>
/// Create a hex string from an Int64 value
/// </summary>
public static string ToHexString(long data)
{
return ToHexString(BitConverter.GetBytes(data));
}
/// <summary>
/// Create a hex string from an array of bytes
/// </summary>
public static string ToHexString(byte[] data)
{
char[] c = new char[data.Length * 2];
byte b;
for (int i = 0; i < data.Length; ++i)
{
b = ((byte)(data[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(data[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
/// <summary>
/// Gets the local broadcast address
/// </summary>
public static IPAddress GetBroadcastAddress()
{
#if __ANDROID__
try{
Android.Net.Wifi.WifiManager wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.App.Activity.WifiService);
if (wifi.IsWifiEnabled)
{
var dhcp = wifi.DhcpInfo;
int broadcast = (dhcp.IpAddress & dhcp.Netmask) | ~dhcp.Netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
{
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
}
return new IPAddress(quads);
}
}
catch // Catch Access Denied Errors
{
return IPAddress.Broadcast;
}
#endif
#if IS_FULL_NET_AVAILABLE
try
{
NetworkInterface ni = GetNetworkInterface();
if (ni == null)
{
return null;
}
IPInterfaceProperties properties = ni.GetIPProperties();
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
{
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
{
var mask = unicastAddress.IPv4Mask;
byte[] ipAdressBytes = unicastAddress.Address.GetAddressBytes();
byte[] subnetMaskBytes = mask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
}
}
catch // Catch any errors
{
return IPAddress.Broadcast;
}
#endif
return IPAddress.Broadcast;
}
/// <summary>
/// Gets my local IP address (not necessarily external) and subnet mask
/// </summary>
public static IPAddress GetMyAddress(out IPAddress mask)
{
mask = null;
#if __ANDROID__
try
{
Android.Net.Wifi.WifiManager wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.App.Activity.WifiService);
if (!wifi.IsWifiEnabled) return null;
var dhcp = wifi.DhcpInfo;
int addr = dhcp.IpAddress;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
{
quads[k] = (byte) ((addr >> k * 8) & 0xFF);
}
return new IPAddress(quads);
}
catch // Catch Access Denied errors
{
return null;
}
#endif
#if IS_FULL_NET_AVAILABLE
NetworkInterface ni = GetNetworkInterface();
if (ni == null)
{
mask = null;
return null;
}
IPInterfaceProperties properties = ni.GetIPProperties();
foreach (UnicastIPAddressInformation unicastAddress in properties.UnicastAddresses)
{
if (unicastAddress != null && unicastAddress.Address != null && unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork)
{
mask = unicastAddress.IPv4Mask;
return unicastAddress.Address;
}
}
#endif
return null;
}
/// <summary>
/// Returns true if the IPEndPoint supplied is on the same subnet as this host
/// </summary>
public static bool IsLocal(IPEndPoint endPoint)
{
if (endPoint == null)
return false;
return IsLocal(endPoint.Address);
}
/// <summary>
/// Returns true if the IPAddress supplied is on the same subnet as this host
/// </summary>
public static bool IsLocal(IPAddress remote)
{
if (remote.AddressFamily == AddressFamily.InterNetworkV6)
{
// TODO: Can this be made to work? Do we even care for SS14?
return false;
}
IPAddress mask;
IPAddress local = GetMyAddress(out mask);
if (mask == null)
return false;
uint maskBits = BitConverter.ToUInt32(mask.GetAddressBytes(), 0);
uint remoteBits = BitConverter.ToUInt32(remote.GetAddressBytes(), 0);
uint localBits = BitConverter.ToUInt32(local.GetAddressBytes(), 0);
// compare network portions
return ((remoteBits & maskBits) == (localBits & maskBits));
}
/// <summary>
/// Returns how many bits are necessary to hold a certain number
/// </summary>
[CLSCompliant(false)]
public static int BitsToHoldUInt(uint value)
{
int bits = 1;
while ((value >>= 1) != 0)
bits++;
return bits;
}
/// <summary>
/// Returns how many bytes are required to hold a certain number of bits
/// </summary>
public static int BytesToHoldBits(int numBits)
{
return (numBits + 7) / 8;
}
internal static UInt32 SwapByteOrder(UInt32 value)
{
return
((value & 0xff000000) >> 24) |
((value & 0x00ff0000) >> 8) |
((value & 0x0000ff00) << 8) |
((value & 0x000000ff) << 24);
}
internal static UInt64 SwapByteOrder(UInt64 value)
{
return
((value & 0xff00000000000000L) >> 56) |
((value & 0x00ff000000000000L) >> 40) |
((value & 0x0000ff0000000000L) >> 24) |
((value & 0x000000ff00000000L) >> 8) |
((value & 0x00000000ff000000L) << 8) |
((value & 0x0000000000ff0000L) << 24) |
((value & 0x000000000000ff00L) << 40) |
((value & 0x00000000000000ffL) << 56);
}
internal static bool CompareElements(byte[] one, byte[] two)
{
if (one.Length != two.Length)
return false;
for (int i = 0; i < one.Length; i++)
if (one[i] != two[i])
return false;
return true;
}
/// <summary>
/// Convert a hexadecimal string to a byte array
/// </summary>
public static byte[] ToByteArray(String hexString)
{
byte[] retval = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i += 2)
retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
return retval;
}
/// <summary>
/// Converts a number of bytes to a shorter, more readable string representation
/// </summary>
public static string ToHumanReadable(long bytes)
{
if (bytes < 4000) // 1-4 kb is printed in bytes
return bytes + " bytes";
if (bytes < 1000 * 1000) // 4-999 kb is printed in kb
return Math.Round(((double)bytes / 1000.0), 2) + " kilobytes";
return Math.Round(((double)bytes / (1000.0 * 1000.0)), 2) + " megabytes"; // else megabytes
}
internal static int RelativeSequenceNumber(int nr, int expected)
{
return (nr - expected + NetConstants.NumSequenceNumbers + (NetConstants.NumSequenceNumbers / 2)) % NetConstants.NumSequenceNumbers - (NetConstants.NumSequenceNumbers / 2);
}
/// <summary>
/// Gets the window size used internally in the library for a certain delivery method
/// </summary>
public static int GetWindowSize(NetDeliveryMethod method)
{
switch (method)
{
case NetDeliveryMethod.Unknown:
return 0;
case NetDeliveryMethod.Unreliable:
case NetDeliveryMethod.UnreliableSequenced:
return NetConstants.UnreliableWindowSize;
case NetDeliveryMethod.ReliableOrdered:
return NetConstants.ReliableOrderedWindowSize;
case NetDeliveryMethod.ReliableSequenced:
case NetDeliveryMethod.ReliableUnordered:
default:
return NetConstants.DefaultWindowSize;
}
}
// shell sort
internal static void SortMembersList(System.Reflection.MemberInfo[] list)
{
int h;
int j;
System.Reflection.MemberInfo tmp;
h = 1;
while (h * 3 + 1 <= list.Length)
h = 3 * h + 1;
while (h > 0)
{
for (int i = h - 1; i < list.Length; i++)
{
tmp = list[i];
j = i;
while (true)
{
if (j >= h)
{
if (string.Compare(list[j - h].Name, tmp.Name, StringComparison.InvariantCulture) > 0)
{
list[j] = list[j - h];
j -= h;
}
else
break;
}
else
break;
}
list[j] = tmp;
}
h /= 3;
}
}
internal static NetDeliveryMethod GetDeliveryMethod(NetMessageType mtp)
{
if (mtp >= NetMessageType.UserReliableOrdered1)
return NetDeliveryMethod.ReliableOrdered;
else if (mtp >= NetMessageType.UserReliableSequenced1)
return NetDeliveryMethod.ReliableSequenced;
else if (mtp >= NetMessageType.UserReliableUnordered)
return NetDeliveryMethod.ReliableUnordered;
else if (mtp >= NetMessageType.UserSequenced1)
return NetDeliveryMethod.UnreliableSequenced;
return NetDeliveryMethod.Unreliable;
}
/// <summary>
/// Creates a comma delimited string from a lite of items
/// </summary>
public static string MakeCommaDelimitedList<T>(IList<T> list)
{
var cnt = list.Count;
StringBuilder bdr = new StringBuilder(cnt * 5); // educated guess
for(int i=0;i<cnt;i++)
{
bdr.Append(list[i].ToString());
if (i != cnt - 1)
bdr.Append(", ");
}
return bdr.ToString();
}
}
}

View File

@@ -1,37 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Lidgren.Network")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Lidgren.Network")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("78f2a988-46e1-4fc4-b7b4-dd2cbe46da6a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2012.1.7.0")]
[assembly: AssemblyFileVersion("2012.1.7.0")]
[assembly: System.CLSCompliant(true)]

View File

@@ -1,11 +0,0 @@
using System;
namespace Lidgren.Network
{
internal abstract class SenderChannelBase
{
internal abstract NetSendResult Send(float now, NetOutgoingMessage message);
internal abstract void SendQueuedMessages(float now);
internal abstract void Reset();
}
}

View File

@@ -0,0 +1,5 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Analyzers\Robust.Analyzers.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

View File

@@ -20,4 +20,10 @@
<PropertyGroup Condition="'$(FullRelease)' == 'True'">
<DefineConstants>$(DefineConstants);FULL_RELEASE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DefineConstants>$(DefineConstants);EXCEPTION_TOLERANCE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(EnableClientScripting)' == 'True'">
<DefineConstants>$(DefineConstants);CLIENT_SCRIPTING</DefineConstants>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<Project>
<!-- Engine-specific properties. Content should not use this file. -->
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,27 +1,3 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<RobustToolsPath>$(MSBuildThisFileDirectory)/../Tools/</RobustToolsPath>
</PropertyGroup>
<Target Name="CopySwnfd">
<CombinePath BasePath="$(RobustToolsPath)" Paths="download_swnfd.py">
<Output TaskParameter="CombinedPaths" PropertyName="ScriptPath" />
</CombinePath>
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) &quot;$(ScriptPath)&quot; $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download swnfd because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="CopyGlfw">
<CombinePath BasePath="$(RobustToolsPath)" Paths="download_glfw.py">
<Output TaskParameter="CombinedPaths" PropertyName="ScriptPath" />
</CombinePath>
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) &quot;$(ScriptPath)&quot; $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download GLFW because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="CopyMiscDependencies">
<CombinePath BasePath="$(RobustToolsPath)" Paths="download_misc_dependencies.py">
<Output TaskParameter="CombinedPaths" PropertyName="ScriptPath" />
</CombinePath>
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) &quot;$(ScriptPath)&quot; $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download misc dependencies because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="ClientAfterBuild" DependsOnTargets="CopyMiscDependencies;CopySwnfd;CopyGlfw" />
<Import Project="Robust.Analyzers.targets" />
</Project>

View File

@@ -26,6 +26,9 @@
<TargetOS Condition="'$(TargetOS)' == ''">$(ActualOS)</TargetOS>
<Python>python3</Python>
<Python Condition="'$(ActualOS)' == 'Windows'">py -3</Python>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<EnableClientScripting>True</EnableClientScripting>
<!-- Client scripting is disabled on full release builds for security and size reasons. -->
<EnableClientScripting Condition="'$(FullRelease)' == 'True'">False</EnableClientScripting>
</PropertyGroup>
</Project>

65
MSBuild/XamlIL.targets Normal file
View File

@@ -0,0 +1,65 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<!-- Avoid MSBuild adding a None entry for XAML files because they'd show up TWICE in the project view. -->
<DefaultItemExcludes>**/*.xaml</DefaultItemExcludes>
<RobustUseExternalMSBuild>true</RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild>$(RobustUseExternalMSBuild)</_RobustUseExternalMSBuild>
<_RobustUseExternalMSBuild Condition="'$(_RobustForceInternalMSBuild)' == 'true'">false</_RobustUseExternalMSBuild>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml"/>
<AdditionalFiles Include="**\*.xaml"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.NameGenerator\Robust.Client.NameGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\Robust.Client.Injectors.csproj" ReferenceOutputAssembly="false"/>
</ItemGroup>
<UsingTask
Condition="'$(_RobustUseExternalMSBuild)' != 'true' And $(DesignTimeBuild) != true"
TaskName="CompileRobustXamlTask"
AssemblyFile="$(MSBuildThisFileDirectory)\..\Robust.Client.Injectors\bin\$(Configuration)\netstandard2.0\Robust.Client.Injectors.dll"/>
<Target
Name="CompileRobustXaml"
Condition="Exists('@(IntermediateAssembly)')"
AfterTargets="AfterCompile"
Inputs="@(IntermediateAssembly);@(ReferencePathWithRefAssemblies)"
Outputs="$(IntermediateOutputPath)XAML/doot">
<PropertyGroup>
<RobustXamlReferencesTemporaryFilePath Condition="'$(RobustXamlReferencesTemporaryFilePath)' == ''">$(IntermediateOutputPath)XAML/references</RobustXamlReferencesTemporaryFilePath>
<RobustXamlOriginalCopyFilePath Condition="'$(RobustXamlOriginalCopyFilePath)' == ''">$(IntermediateOutputPath)XAML/original.dll</RobustXamlOriginalCopyFilePath>
</PropertyGroup>
<WriteLinesToFile
Condition="'$(_RobustForceInternalMSBuild)' != 'true'"
File="$(RobustXamlReferencesTemporaryFilePath)"
Lines="@(ReferencePathWithRefAssemblies)"
Overwrite="true"/>
<!--
UpdateBuildIndicator is done so that we can use MSBuild Inputs and Outputs on the target
to avoid unecessary execution of this target
Saves compile time if e.g. ONLY Robust.Client changes (Content.Client doesn't have to re-xaml).
-->
<CompileRobustXamlTask
Condition="'$(_RobustUseExternalMSBuild)' != 'true'"
AssemblyFile="@(IntermediateAssembly)"
ReferencesFilePath="$(RobustXamlReferencesTemporaryFilePath)"
OriginalCopyPath="$(RobustXamlOriginalCopyFilePath)"
ProjectDirectory="$(MSBuildProjectDirectory)"
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
UpdateBuildIndicator="$(IntermediateOutputPath)XAML/doot"/>
<PropertyGroup>
<DOTNET_HOST_PATH Condition="'$(DOTNET_HOST_PATH)' == ''">dotnet</DOTNET_HOST_PATH>
</PropertyGroup>
<Exec
Condition="'$(_RobustUseExternalMSBuild)' == 'true'"
Command="&quot;$(DOTNET_HOST_PATH)&quot; msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileRobustXaml /p:_RobustForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:TargetFramework=$(TargetFramework) /p:BuildProjectReferences=false"/>
</Target>
</Project>

1
ManagedHttpListener Submodule

Submodule ManagedHttpListener added at f2aa590fec

1
NetSerializer Submodule

Submodule NetSerializer added at 2d4f8b5611

Some files were not shown because too many files have changed in this diff Show More