From e31141a804dcd5d7a6167a11036f31457a4177fa Mon Sep 17 00:00:00 2001 From: FirstGearGames Date: Sat, 3 Feb 2024 10:55:51 -0500 Subject: [PATCH] 4.1.0 - Added Edgegap to FishNet plugins. - Removed several obsoletes due for removal. - Reversed DefaultObjectPool changes from V4 beta releases. - Changed several ReadOnlyCollection to ReadOnlyList for performance gains. - Improved NetworkObject inspector OwnerInterpolation now functions. - Fixed jitter on Prediction 2 smoothing, as well incorrect offet. --- .../Rigidbody/PredictionV2_RB.unity | 280 +- .../Prefabs/RigidbodyPrediction.prefab | 2 +- .../Scripts/RigidbodyPredictionV2.cs | 23 +- .../Scripts/SpringBoard/SpringBoard.cs | 71 - .../Scripts/SpringBoard.meta => Plugins.meta} | 2 +- Assets/FishNet/Plugins/Edgegap.meta | 8 + .../FishNet/Plugins/Edgegap/Dependencies.meta | 3 + .../Edgegap/Dependencies/HttpEncoder.cs | 704 +++++ .../Edgegap/Dependencies/HttpEncoder.cs.meta | 3 + .../Edgegap/Dependencies/HttpUtility.cs | 230 ++ .../Edgegap/Dependencies/HttpUtility.cs.meta | 3 + Assets/FishNet/Plugins/Edgegap/Editor.meta | 8 + .../FishNet/Plugins/Edgegap/Editor/Api.meta | 8 + .../Edgegap/Editor/Api/EdgegapApiBase.cs | 280 ++ .../Editor/Api/EdgegapApiBase.cs.meta} | 2 +- .../Edgegap/Editor/Api/EdgegapAppApi.cs | 148 + .../Edgegap/Editor/Api/EdgegapAppApi.cs.meta | 11 + .../Editor/Api/EdgegapDeploymentsApi.cs | 177 ++ .../Editor/Api/EdgegapDeploymentsApi.cs.meta | 11 + .../Edgegap/Editor/Api/EdgegapIpApi.cs | 47 + .../Edgegap/Editor/Api/EdgegapIpApi.cs.meta | 11 + .../Edgegap/Editor/Api/EdgegapWizardApi.cs | 52 + .../Editor/Api/EdgegapWizardApi.cs.meta | 11 + .../Plugins/Edgegap/Editor/Api/Models.meta | 8 + .../Edgegap/Editor/Api/Models/AppPortsData.cs | 28 + .../Editor/Api/Models/AppPortsData.cs.meta | 11 + .../Editor/Api/Models/DeploymentPortsData.cs | 29 + .../Api/Models/DeploymentPortsData.cs.meta | 3 + .../Edgegap/Editor/Api/Models/LocationData.cs | 28 + .../Editor/Api/Models/LocationData.cs.meta | 11 + .../Edgegap/Editor/Api/Models/ProtocolType.cs | 18 + .../Editor/Api/Models/ProtocolType.cs.meta | 11 + .../Edgegap/Editor/Api/Models/Requests.meta | 8 + .../Api/Models/Requests/CreateAppRequest.cs | 55 + .../Models/Requests/CreateAppRequest.cs.meta | 11 + .../Requests/CreateAppVersionRequest.cs | 225 ++ .../Requests/CreateAppVersionRequest.cs.meta | 11 + .../Requests/CreateDeploymentRequest.cs | 63 + .../Requests/CreateDeploymentRequest.cs.meta | 11 + .../Requests/UpdateAppVersionRequest.cs | 175 ++ .../Requests/UpdateAppVersionRequest.cs.meta | 11 + .../Edgegap/Editor/Api/Models/Results.meta | 8 + .../Models/Results/CreateDeploymentResult.cs | 53 + .../Results/CreateDeploymentResult.cs.meta | 11 + .../Api/Models/Results/EdgegapErrorResult.cs | 12 + .../Models/Results/EdgegapErrorResult.cs.meta | 11 + .../Api/Models/Results/EdgegapHttpResult.cs | 118 + .../Models/Results/EdgegapHttpResult.cs.meta | 11 + .../Api/Models/Results/GetCreateAppResult.cs | 31 + .../Models/Results/GetCreateAppResult.cs.meta | 11 + .../Results/GetDeploymentStatusResult.cs | 89 + .../Results/GetDeploymentStatusResult.cs.meta | 11 + .../Results/GetRegistryCredentialsResult.cs | 22 + .../GetRegistryCredentialsResult.cs.meta | 11 + .../Models/Results/GetYourPublicIpResult.cs | 14 + .../Results/GetYourPublicIpResult.cs.meta | 11 + .../Results/StopActiveDeploymentResult.cs | 89 + .../StopActiveDeploymentResult.cs.meta | 11 + .../Models/Results/UpsertAppVersionResult.cs | 165 + .../Results/UpsertAppVersionResult.cs.meta | 11 + .../Edgegap/Editor/Api/Models/SessionData.cs | 28 + .../Editor/Api/Models/SessionData.cs.meta | 11 + .../Plugins/Edgegap/Editor/ButtonShaker.cs | 37 + .../Edgegap/Editor/ButtonShaker.cs.meta | 11 + .../Edgegap/Editor/EdgegapBuildUtils.cs | 298 ++ .../Edgegap/Editor/EdgegapBuildUtils.cs.meta | 11 + .../Edgegap/Editor/EdgegapScriptEditor.cs | 25 + .../Editor/EdgegapScriptEditor.cs.meta | 11 + .../Edgegap/Editor/EdgegapServerData.uss | 81 + .../Edgegap/Editor/EdgegapServerData.uss.meta | 11 + .../Editor/EdgegapServerDataManager.cs | 240 ++ .../Editor/EdgegapServerDataManager.cs.meta | 11 + .../Edgegap/Editor/EdgegapToolScript.cs | 12 + .../Edgegap/Editor/EdgegapToolScript.cs.meta | 11 + .../Plugins/Edgegap/Editor/EdgegapWindow.cs | 983 ++++++ .../Edgegap/Editor/EdgegapWindow.cs.meta | 11 + .../Plugins/Edgegap/Editor/EdgegapWindow.uss | 213 ++ .../Edgegap/Editor/EdgegapWindow.uss.meta | 11 + .../Plugins/Edgegap/Editor/EdgegapWindow.uxml | 102 + .../Edgegap/Editor/EdgegapWindow.uxml.meta | 10 + .../Edgegap/Editor/EdgegapWindowMetadata.cs | 173 ++ .../Editor/EdgegapWindowMetadata.cs.meta | 11 + .../Plugins/Edgegap/Editor/EdgegapWindowV2.cs | 1755 +++++++++++ .../Edgegap/Editor/EdgegapWindowV2.cs.meta | 11 + .../FishNet/Plugins/Edgegap/Editor/Fonts.meta | 8 + .../Edgegap/Editor/Fonts/BaronNeue SDF.asset | 2660 ++++++++++++++++ .../Editor/Fonts/BaronNeue SDF.asset.meta | 8 + .../Editor/Fonts/Spartan-Regular SDF.asset | 2727 ++++++++++++++++ .../Fonts/Spartan-Regular SDF.asset.meta | 8 + .../Editor/Fonts/Spartan-SemiBold SDF.asset | 2739 +++++++++++++++++ .../Fonts/Spartan-SemiBold SDF.asset.meta | 8 + .../Plugins/Edgegap/Editor/Fonts/Src.meta | 8 + .../Edgegap/Editor/Fonts/Src/BaronNeue.otf | Bin 0 -> 27176 bytes .../Editor/Fonts/Src/BaronNeue.otf.meta | 21 + .../Edgegap/Editor/Fonts/Src/Spartan.meta | 8 + .../Fonts/Src/Spartan/Spartan-Regular.ttf | Bin 0 -> 38384 bytes .../Src/Spartan/Spartan-Regular.ttf.meta | 21 + .../Fonts/Src/Spartan/Spartan-SemiBold.ttf | Bin 0 -> 38392 bytes .../Src/Spartan/Spartan-SemiBold.ttf.meta | 21 + .../Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf | Bin 0 -> 205748 bytes .../Editor/Fonts/Src/UbuntuMono-R.ttf.meta | 21 + .../Editor/Fonts/UbuntuMono-R SDF.asset | 2723 ++++++++++++++++ .../Editor/Fonts/UbuntuMono-R SDF.asset.meta | 8 + .../Plugins/Edgegap/Editor/Images.meta | 8 + .../Edgegap/Editor/Images/clipboard-128.png | Bin 0 -> 3083 bytes .../Editor/Images/clipboard-128.png.meta | 140 + .../Images/logo_transparent_400_alpha25.png | Bin 0 -> 13034 bytes .../logo_transparent_400_alpha25.png.meta | 96 + Assets/FishNet/Plugins/Edgegap/Enums.meta | 8 + .../Plugins/Edgegap/Enums/ApiEnvironment.cs | 71 + .../Edgegap/Enums/ApiEnvironment.cs.meta | 11 + .../Plugins/Edgegap/Enums/ServerStatus.cs | 84 + .../Edgegap/Enums/ServerStatus.cs.meta | 11 + .../Plugins/Edgegap/Enums/ToolState.cs | 46 + .../Plugins/Edgegap/Enums/ToolState.cs.meta | 11 + Assets/FishNet/Plugins/Edgegap/Models.meta | 8 + .../Models/AppVersionUpdatePatchData.cs | 24 + .../Models/AppVersionUpdatePatchData.cs.meta | 11 + .../Plugins/Edgegap/Models/DeployPostData.cs | 24 + .../Edgegap/Models/DeployPostData.cs.meta | 11 + .../FishNet/Plugins/Edgegap/Models/SDK.meta | 8 + .../Models/SDK/ApiModelContainercrashdata.cs | 63 + .../SDK/ApiModelContainercrashdata.cs.meta | 11 + .../Models/SDK/ApiModelContainerlogs.cs | 71 + .../Models/SDK/ApiModelContainerlogs.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/AppCreation.cs | 53 + .../Edgegap/Models/SDK/AppCreation.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/AppVersion.cs | 240 ++ .../Edgegap/Models/SDK/AppVersion.cs.meta | 11 + .../SDK/AppVersionCreateSessionConfig.cs | 81 + .../SDK/AppVersionCreateSessionConfig.cs.meta | 11 + .../Edgegap/Models/SDK/AppVersionEnv.cs | 63 + .../Edgegap/Models/SDK/AppVersionEnv.cs.meta | 11 + .../Edgegap/Models/SDK/AppVersionPort.cs | 81 + .../Edgegap/Models/SDK/AppVersionPort.cs.meta | 11 + .../Edgegap/Models/SDK/AppVersionProbe.cs | 54 + .../Models/SDK/AppVersionProbe.cs.meta | 11 + .../Edgegap/Models/SDK/AppVersionUpdate.cs | 240 ++ .../Models/SDK/AppVersionUpdate.cs.meta | 11 + .../SDK/AppVersionUpdateSessionConfig.cs | 81 + .../SDK/AppVersionUpdateSessionConfig.cs.meta | 11 + .../Models/SDK/AppVersionWhitelistEntry.cs | 72 + .../SDK/AppVersionWhitelistEntry.cs.meta | 11 + .../SDK/AppVersionWhitelistEntryPayload.cs | 63 + .../AppVersionWhitelistEntryPayload.cs.meta | 11 + .../SDK/AppVersionWhitelistEntrySuccess.cs | 53 + .../AppVersionWhitelistEntrySuccess.cs.meta | 11 + .../Models/SDK/AppVersionWhitelistResponse.cs | 44 + .../SDK/AppVersionWhitelistResponse.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/AppVersions.cs | 52 + .../Edgegap/Models/SDK/AppVersions.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Application.cs | 81 + .../Edgegap/Models/SDK/Application.cs.meta | 11 + .../Edgegap/Models/SDK/ApplicationPatch.cs | 63 + .../Models/SDK/ApplicationPatch.cs.meta | 11 + .../Edgegap/Models/SDK/ApplicationPost.cs | 63 + .../Models/SDK/ApplicationPost.cs.meta | 11 + .../Edgegap/Models/SDK/Applications.cs | 44 + .../Edgegap/Models/SDK/Applications.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/BaseModel.cs | 52 + .../Edgegap/Models/SDK/BaseModel.cs.meta | 11 + .../Edgegap/Models/SDK/BulkSessionDelete.cs | 54 + .../Models/SDK/BulkSessionDelete.cs.meta | 11 + .../Edgegap/Models/SDK/BulkSessionPost.cs | 54 + .../Models/SDK/BulkSessionPost.cs.meta | 11 + .../Models/SDK/ComponentCredentials.cs | 54 + .../Models/SDK/ComponentCredentials.cs.meta | 11 + .../Models/SDK/ContainerLogStorageModel.cs | 54 + .../SDK/ContainerLogStorageModel.cs.meta | 11 + .../Models/SDK/CustomBulkSessionModel.cs | 54 + .../Models/SDK/CustomBulkSessionModel.cs.meta | 11 + .../Models/SDK/CustomBulkSessionsModel.cs | 44 + .../SDK/CustomBulkSessionsModel.cs.meta | 11 + .../Models/SDK/CustomSessionDeleteModel.cs | 45 + .../SDK/CustomSessionDeleteModel.cs.meta | 11 + .../Edgegap/Models/SDK/CustomSessionModel.cs | 45 + .../Models/SDK/CustomSessionModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Delete.cs | 54 + .../Plugins/Edgegap/Models/SDK/Delete.cs.meta | 11 + .../Edgegap/Models/SDK/DeployEnvModel.cs | 63 + .../Edgegap/Models/SDK/DeployEnvModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/DeployModel.cs | 180 ++ .../Edgegap/Models/SDK/DeployModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Deployment.cs | 134 + .../Edgegap/Models/SDK/Deployment.cs.meta | 11 + .../Edgegap/Models/SDK/DeploymentLocation.cs | 99 + .../Models/SDK/DeploymentLocation.cs.meta | 11 + .../Models/SDK/DeploymentSessionContext.cs | 90 + .../SDK/DeploymentSessionContext.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Deployments.cs | 72 + .../Edgegap/Models/SDK/Deployments.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Error.cs | 45 + .../Plugins/Edgegap/Models/SDK/Error.cs.meta | 11 + .../Edgegap/Models/SDK/GeoIpListModel.cs | 63 + .../Edgegap/Models/SDK/GeoIpListModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Location.cs | 108 + .../Edgegap/Models/SDK/Location.cs.meta | 11 + .../Edgegap/Models/SDK/LocationModel.cs | 54 + .../Edgegap/Models/SDK/LocationModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Locations.cs | 53 + .../Edgegap/Models/SDK/Locations.cs.meta | 11 + .../Models/SDK/MatchmakerComponentCreate.cs | 81 + .../SDK/MatchmakerComponentCreate.cs.meta | 11 + .../SDK/MatchmakerComponentEnvListResponse.cs | 54 + ...MatchmakerComponentEnvListResponse.cs.meta | 11 + .../SDK/MatchmakerComponentEnvsCreate.cs | 54 + .../SDK/MatchmakerComponentEnvsCreate.cs.meta | 11 + .../SDK/MatchmakerComponentEnvsResponse.cs | 54 + .../MatchmakerComponentEnvsResponse.cs.meta | 11 + .../SDK/MatchmakerComponentEnvsUpdate.cs | 54 + .../SDK/MatchmakerComponentEnvsUpdate.cs.meta | 11 + .../SDK/MatchmakerComponentListResponse.cs | 54 + .../MatchmakerComponentListResponse.cs.meta | 11 + .../Models/SDK/MatchmakerComponentResponse.cs | 81 + .../SDK/MatchmakerComponentResponse.cs.meta | 11 + .../Models/SDK/MatchmakerComponentUpdate.cs | 81 + .../SDK/MatchmakerComponentUpdate.cs.meta | 11 + .../Edgegap/Models/SDK/MatchmakerCreate.cs | 45 + .../Models/SDK/MatchmakerCreate.cs.meta | 11 + .../Models/SDK/MatchmakerListResponse.cs | 54 + .../Models/SDK/MatchmakerListResponse.cs.meta | 11 + .../SDK/MatchmakerManagedReleaseCreate.cs | 45 + .../MatchmakerManagedReleaseCreate.cs.meta | 11 + .../SDK/MatchmakerManagedReleaseResponse.cs | 45 + .../MatchmakerManagedReleaseResponse.cs.meta | 11 + .../SDK/MatchmakerManagedReleaseUpdate.cs | 45 + .../MatchmakerManagedReleaseUpdate.cs.meta | 11 + .../SDK/MatchmakerReleaseConfigCreate.cs | 54 + .../SDK/MatchmakerReleaseConfigCreate.cs.meta | 11 + .../SDK/MatchmakerReleaseConfigResponse.cs | 54 + .../MatchmakerReleaseConfigResponse.cs.meta | 11 + .../SDK/MatchmakerReleaseConfigUpdate.cs | 54 + .../SDK/MatchmakerReleaseConfigUpdate.cs.meta | 11 + .../Models/SDK/MatchmakerReleaseCreate.cs | 63 + .../SDK/MatchmakerReleaseCreate.cs.meta | 11 + .../Models/SDK/MatchmakerReleaseCreateBase.cs | 45 + .../SDK/MatchmakerReleaseCreateBase.cs.meta | 11 + .../Models/SDK/MatchmakerReleaseResponse.cs | 63 + .../SDK/MatchmakerReleaseResponse.cs.meta | 11 + .../SDK/MatchmakerReleaseResponseBase.cs | 63 + .../SDK/MatchmakerReleaseResponseBase.cs.meta | 11 + .../Models/SDK/MatchmakerReleaseUpdate.cs | 63 + .../SDK/MatchmakerReleaseUpdate.cs.meta | 11 + .../Models/SDK/MatchmakerReleaseUpdateBase.cs | 45 + .../SDK/MatchmakerReleaseUpdateBase.cs.meta | 11 + .../Edgegap/Models/SDK/MatchmakerResponse.cs | 45 + .../Models/SDK/MatchmakerResponse.cs.meta | 11 + .../Edgegap/Models/SDK/MatchmakerUpdate.cs | 45 + .../Models/SDK/MatchmakerUpdate.cs.meta | 11 + .../Edgegap/Models/SDK/MetricsModel.cs | 60 + .../Edgegap/Models/SDK/MetricsModel.cs.meta | 11 + .../Edgegap/Models/SDK/MetricsResponse.cs | 68 + .../Models/SDK/MetricsResponse.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Monitor.cs | 99 + .../Edgegap/Models/SDK/Monitor.cs.meta | 11 + .../Edgegap/Models/SDK/NetworkMetricsModel.cs | 52 + .../Models/SDK/NetworkMetricsModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Pagination.cs | 89 + .../Edgegap/Models/SDK/Pagination.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Paginator.cs | 45 + .../Edgegap/Models/SDK/Paginator.cs.meta | 11 + .../Edgegap/Models/SDK/PatchSessionModel.cs | 45 + .../Models/SDK/PatchSessionModel.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/PortMapping.cs | 99 + .../Edgegap/Models/SDK/PortMapping.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Request.cs | 135 + .../Edgegap/Models/SDK/Request.cs.meta | 11 + .../Edgegap/Models/SDK/SelectorEnvModel.cs | 54 + .../Models/SDK/SelectorEnvModel.cs.meta | 11 + .../Edgegap/Models/SDK/SelectorModel.cs | 63 + .../Edgegap/Models/SDK/SelectorModel.cs.meta | 11 + .../Edgegap/Models/SDK/SessionContext.cs | 108 + .../Edgegap/Models/SDK/SessionContext.cs.meta | 11 + .../Edgegap/Models/SDK/SessionDelete.cs | 63 + .../Edgegap/Models/SDK/SessionDelete.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/SessionGet.cs | 161 + .../Edgegap/Models/SDK/SessionGet.cs.meta | 11 + .../Edgegap/Models/SDK/SessionModel.cs | 144 + .../Edgegap/Models/SDK/SessionModel.cs.meta | 11 + .../Edgegap/Models/SDK/SessionRequest.cs | 90 + .../Edgegap/Models/SDK/SessionRequest.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/SessionUser.cs | 63 + .../Edgegap/Models/SDK/SessionUser.cs.meta | 11 + .../Edgegap/Models/SDK/SessionUserContext.cs | 45 + .../Models/SDK/SessionUserContext.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Sessions.cs | 63 + .../Edgegap/Models/SDK/Sessions.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/StaticSites.cs | 90 + .../Edgegap/Models/SDK/StaticSites.cs.meta | 11 + .../Edgegap/Models/SDK/StaticSitesList.cs | 53 + .../Models/SDK/StaticSitesList.cs.meta | 11 + .../Plugins/Edgegap/Models/SDK/Status.cs | 215 ++ .../Plugins/Edgegap/Models/SDK/Status.cs.meta | 11 + .../Edgegap/Models/SDK/TotalMetricsModel.cs | 68 + .../Models/SDK/TotalMetricsModel.cs.meta | 11 + .../NetworkTransform/NetworkTransform.cs | 3 +- .../Prediction/PredictedObject.Rigidbodies.cs | 2 +- .../Component/Prediction/PredictedObject.cs | 29 - .../Component/Spawning/PlayerSpawner.cs | 1 - .../Component/Utility/DefaultScene.cs | 1 - .../Runtime/Managing/NetworkManager.cs | 4 +- .../Object/PrefabObjects/DualPrefabObjects.cs | 4 +- .../Managing/Observing/ObserverManager.cs | 2 - .../Object/NetworkObject.Prediction.cs | 2 +- .../FishNet/Runtime/Object/NetworkObject.cs | 16 +- .../Runtime/Object/Prediction/MoveRates.cs | 10 +- .../Prediction/PredictionTickSmoother.cs | 26 +- .../Prediction/TransformTickSmoother.cs | 2 +- .../Runtime/Observing/NetworkObserver.cs | 1 - .../Scripts/RollbackManager.cs | 10 - .../Runtime/Utility/DetachableTickSmoother.cs | 2 +- .../Utility/Performance/DefaultObjectPool.cs | 18 +- Assets/FishNet/VERSION.txt | 2 +- Assets/FishNet/package.json | 5 +- FishNet V4.sln | 6 + 315 files changed, 26163 insertions(+), 437 deletions(-) delete mode 100644 Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs rename Assets/FishNet/{Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard.meta => Plugins.meta} (77%) create mode 100644 Assets/FishNet/Plugins/Edgegap.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Dependencies.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs rename Assets/FishNet/{Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs.meta => Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs.meta} (83%) create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.uss create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.uss.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.uxml create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.uxml.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowMetadata.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowMetadata.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/BaronNeue SDF.asset create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/BaronNeue SDF.asset.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Spartan-Regular SDF.asset create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Spartan-Regular SDF.asset.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Spartan-SemiBold SDF.asset create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Spartan-SemiBold SDF.asset.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/BaronNeue.otf create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/BaronNeue.otf.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/Spartan.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/Spartan/Spartan-Regular.ttf create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/Spartan/Spartan-Regular.ttf.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/Spartan/Spartan-SemiBold.ttf create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/Spartan/Spartan-SemiBold.ttf.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/Src/UbuntuMono-R.ttf.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/UbuntuMono-R SDF.asset create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Fonts/UbuntuMono-R SDF.asset.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Images.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Images/clipboard-128.png create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Images/clipboard-128.png.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Images/logo_transparent_400_alpha25.png create mode 100644 Assets/FishNet/Plugins/Edgegap/Editor/Images/logo_transparent_400_alpha25.png.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ServerStatus.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ServerStatus.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ToolState.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Enums/ToolState.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/AppVersionUpdatePatchData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/AppVersionUpdatePatchData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/DeployPostData.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/DeployPostData.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApiModelContainercrashdata.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApiModelContainercrashdata.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApiModelContainerlogs.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApiModelContainerlogs.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppCreation.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppCreation.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersion.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersion.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionCreateSessionConfig.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionCreateSessionConfig.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionEnv.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionEnv.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionPort.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionPort.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionProbe.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionProbe.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionUpdateSessionConfig.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionUpdateSessionConfig.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntry.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntry.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntryPayload.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntryPayload.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntrySuccess.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistEntrySuccess.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersionWhitelistResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersions.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/AppVersions.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Application.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Application.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApplicationPatch.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApplicationPatch.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApplicationPost.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ApplicationPost.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Applications.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Applications.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BaseModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BaseModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BulkSessionDelete.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BulkSessionDelete.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BulkSessionPost.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/BulkSessionPost.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ComponentCredentials.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ComponentCredentials.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ContainerLogStorageModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/ContainerLogStorageModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomBulkSessionModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomBulkSessionModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomBulkSessionsModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomBulkSessionsModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomSessionDeleteModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomSessionDeleteModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomSessionModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/CustomSessionModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Delete.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Delete.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeployEnvModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeployEnvModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeployModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeployModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Deployment.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Deployment.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeploymentLocation.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeploymentLocation.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeploymentSessionContext.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/DeploymentSessionContext.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Deployments.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Deployments.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Error.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Error.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/GeoIpListModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/GeoIpListModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Location.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Location.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/LocationModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/LocationModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Locations.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Locations.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvListResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvListResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentEnvsUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentListResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentListResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerComponentUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerListResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerListResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerManagedReleaseUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseConfigUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseCreate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseCreate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseCreateBase.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseCreateBase.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseResponseBase.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseResponseBase.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseUpdateBase.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerReleaseUpdateBase.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerUpdate.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MatchmakerUpdate.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MetricsModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MetricsModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MetricsResponse.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/MetricsResponse.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Monitor.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Monitor.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/NetworkMetricsModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/NetworkMetricsModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Pagination.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Pagination.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Paginator.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Paginator.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/PatchSessionModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/PatchSessionModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/PortMapping.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/PortMapping.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Request.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Request.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SelectorEnvModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SelectorEnvModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SelectorModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SelectorModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionContext.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionContext.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionDelete.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionDelete.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionGet.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionGet.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionModel.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionRequest.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionRequest.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionUser.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionUser.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionUserContext.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/SessionUserContext.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Sessions.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Sessions.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/StaticSites.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/StaticSites.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/StaticSitesList.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/StaticSitesList.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Status.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/Status.cs.meta create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/TotalMetricsModel.cs create mode 100644 Assets/FishNet/Plugins/Edgegap/Models/SDK/TotalMetricsModel.cs.meta diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/PredictionV2_RB.unity b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/PredictionV2_RB.unity index 69304b57..95002517 100644 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/PredictionV2_RB.unity +++ b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/PredictionV2_RB.unity @@ -139,7 +139,7 @@ MonoBehaviour: _timingType: 0 _allowTickDropping: 0 _maximumFrameTicks: 2 - _tickRate: 30 + _tickRate: 10 _pingInterval: 1 _physicsMode: 1 --- !u!114 &192429405 @@ -154,7 +154,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} m_Name: m_EditorClassIdentifier: - _timeout: 15 _dontRoute: 0 _unreliableMtu: 1023 _ipv4BindAddress: @@ -1144,51 +1143,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1566714753 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1566714754} - - component: {fileID: 1566714755} - m_Layer: 0 - m_Name: Blocker - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!4 &1566714754 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1566714753} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0.16999996, z: 0.029999733} - m_LocalScale: {x: 2.5, y: 0.1, z: 2.5} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1982712574} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &1566714755 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1566714753} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} --- !u!114 &1726381377 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1241,7 +1195,6 @@ Transform: - {fileID: 872683031} - {fileID: 967467090} - {fileID: 1883869627} - - {fileID: 1982712574} m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1426,154 +1379,6 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1883869626} m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1981570032 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1981570033} - - component: {fileID: 1981570035} - - component: {fileID: 1981570034} - - component: {fileID: 1981570037} - - component: {fileID: 1981570036} - m_Layer: 0 - m_Name: Platform - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1981570033 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1981570032} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0.16999996, z: 0.029999733} - m_LocalScale: {x: 2.5, y: 0.1, z: 2.5} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1982712574} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!23 &1981570034 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1981570032} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1981570035 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1981570032} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!65 &1981570036 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1981570032} - m_Material: {fileID: 0} - m_IsTrigger: 1 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 0.95, y: 15, z: 0.95} - m_Center: {x: 0, y: 1.04, z: 0} ---- !u!114 &1981570037 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1981570032} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 026366ce57064ab429b976f32c179b40, type: 3} - m_Name: - m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: 1508709391104412551} - _networkObjectCache: {fileID: 1508709391104412551} - Force: 21 ---- !u!1 &1982712573 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1982712574} - - component: {fileID: 1508709391104412551} - m_Layer: 0 - m_Name: SpringBoard - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1982712574 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1982712573} - m_LocalRotation: {x: 0, y: 0, z: 0.7071068, w: 0.7071068} - m_LocalPosition: {x: 0.75, y: -0.01, z: 4.67} - m_LocalScale: {x: 1, y: 1, z: 2} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1981570033} - - {fileID: 1566714754} - m_Father: {fileID: 1784594015} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90} --- !u!114 &1424052073902602981 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1604,47 +1409,6 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!114 &1508709391104412551 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1982712573} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 1981570037} - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: 0.75, y: -0.01, z: 4.67} - Rotation: {x: 0, y: 0, z: 0.7071068, w: 0.7071068} - LocalScale: {x: 1, y: 1, z: 2} - _isNetworked: 1 - _isSpawnable: 1 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - _enablePrediction: 0 - _predictionType: 0 - _graphicalObject: {fileID: 0} - _enableStateForwarding: 1 - _ownerInterpolation: 1 - _enableTeleport: 0 - _teleportThreshold: 1 - k__BackingField: 6 - k__BackingField: 0 - _scenePathHash: 1828152806 - k__BackingField: 7851856515836051268 - k__BackingField: 5098761234152541391 --- !u!1001 &1712874950459209376 PrefabInstance: m_ObjectHideFlags: 0 @@ -1652,73 +1416,59 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 0} m_Modifications: - - target: {fileID: 1712874951232431508, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431508, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_Name value: Sphere_A objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_RootOrder value: 5 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalPosition.x value: 10.983304 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalPosition.y value: -0.99999994 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalPosition.z value: 11.61 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalRotation.w value: -0.40963268 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalRotation.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalRotation.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalRotation.z value: 0.9122505 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalEulerAnglesHint.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalEulerAnglesHint.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: _scenePathHash value: 1828152806 objectReference: {fileID: 0} - - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, - type: 3} + - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} propertyPath: k__BackingField value: 7851856514066328649 objectReference: {fileID: 0} diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Prefabs/RigidbodyPrediction.prefab b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Prefabs/RigidbodyPrediction.prefab index eb2df83b..8c3ef3ba 100644 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Prefabs/RigidbodyPrediction.prefab +++ b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Prefabs/RigidbodyPrediction.prefab @@ -186,7 +186,7 @@ MonoBehaviour: _ownerInterpolation: 2 _enableTeleport: 0 _teleportThreshold: 1 - k__BackingField: 18 + k__BackingField: 21 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/RigidbodyPredictionV2.cs b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/RigidbodyPredictionV2.cs index f116a39c..4c3ae5ba 100644 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/RigidbodyPredictionV2.cs +++ b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/RigidbodyPredictionV2.cs @@ -11,6 +11,15 @@ namespace FishNet.PredictionV2 { + /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED + * AN EXAMPLE TO FOLLOW. */ + /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED + * AN EXAMPLE TO FOLLOW. */ + /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED + * AN EXAMPLE TO FOLLOW. */ + /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED + * AN EXAMPLE TO FOLLOW. */ + public class RigidbodyPredictionV2 : NetworkBehaviour { #if PREDICTION_V2 @@ -57,8 +66,8 @@ public void Dispose() { } public void SetTick(uint value) => _tick = value; } - [SerializeField] - private float _jumpForce = 15f; + //[SerializeField] + //private float _jumpForce = 15f; [SerializeField] private float _moveRate = 15f; @@ -77,7 +86,6 @@ private void Update() public override void OnStartNetwork() { Rigidbody = GetComponent(); - PRB = new PredictionRigidbody(Rigidbody); base.TimeManager.OnTick += TimeManager_OnTick; base.TimeManager.OnPostTick += TimeManager_OnPostTick; } @@ -143,10 +151,10 @@ private void Move(MoveData md, ReplicateState state = ReplicateState.Invalid, Ch Vector3 forces = new Vector3(md.Horizontal, 0f, md.Vertical) * _moveRate; //PRB.AddForce(forces); forces += Physics.gravity * 3f; - if (md.Jump) - PRB.AddForce(new Vector3(0f, _jumpForce, 0f), ForceMode.Impulse); - //Add gravity to make the object fall faster. - PRB.AddForce(forces); + //if (md.Jump) + // PRB.AddForce(new Vector3(0f, _jumpForce, 0f), ForceMode.Impulse); + ////Add gravity to make the object fall faster. + //PRB.AddForce(forces); //if (IsOwner) @@ -195,7 +203,6 @@ private void Reconciliation(ReconcileData rd, Channel channel = Channel.Unreliab } - public PredictionRigidbody PRB; private bool PrintForClient() => ((!base.IsServerStarted && base.IsOwner) || (base.IsServerStarted && !base.IsOwner)); #endif diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs b/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs deleted file mode 100644 index e38948b0..00000000 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs +++ /dev/null @@ -1,71 +0,0 @@ -using FishNet.CodeGenerating; -using FishNet.Object; -using FishNet.Object.Prediction; -using FishNet.Transporting; -using GameKit.Dependencies.Utilities; -using System.Collections.Generic; -using UnityEngine; - -namespace FishNet.PredictionV2 -{ - - public class SpringBoard : NetworkBehaviour - { -#if PREDICTION_V2 - - public float Force = 20f; - - private void OnTriggerEnter(Collider other) - { - if (other.TryGetComponent(out RigidbodyPredictionV2 rp2)) - { - if (PredictionManager.IsReconciling) - Debug.Log($"Frame {Time.frameCount}. Replay LocalTick {PredictionManager.ClientReplayTick}. Last MdTick {rp2.LastMdTick}. Velocity {rp2.Rigidbody.velocity.magnitude}"); - else - Debug.Log($"Frame {Time.frameCount}. Current LocalTick {TimeManager.LocalTick}. MdTick {rp2.LastMdTick}. Velocity {rp2.Rigidbody.velocity.magnitude}"); - //rp2.Rigidbody.AddForce(Vector3.left * Force, ForceMode.Impulse); - //rp2.Rigidbody.AddImpulseVelocity(Vector3.left * Force); - rp2.PRB.AddForce(Vector3.left * Force, ForceMode.Impulse, true); - } - else - { - Debug.LogError($"SOME OTHER OBJECT HIT"); - } - } - -#endif - } - -} - -public class PredictionRigidbody -{ - public Rigidbody Rigidbody { get; private set; } - - private Vector3 _impulse; - private Vector3 _force; - public PredictionRigidbody(Rigidbody rb) - { - Rigidbody = rb; - } - - - public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force, bool afterSimulation = false) - { - if (afterSimulation) - { - _impulse += force; - return; - } - - if (_impulse != Vector3.zero) - { - Rigidbody.AddForce(_impulse, ForceMode.Impulse); - _impulse = Vector3.zero; - } - - Rigidbody.AddForce(force, mode); - } - - -} \ No newline at end of file diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard.meta b/Assets/FishNet/Plugins.meta similarity index 77% rename from Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard.meta rename to Assets/FishNet/Plugins.meta index 38e7e07a..ab88963a 100644 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard.meta +++ b/Assets/FishNet/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d6eb0d164f8b5d7489599acab540f610 +guid: 1efd6a2198a30b44c98e7a6e48bc92b6 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/FishNet/Plugins/Edgegap.meta b/Assets/FishNet/Plugins/Edgegap.meta new file mode 100644 index 00000000..a7ac9d9b --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aef768f63d4c3c04ab05dfd075406513 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Dependencies.meta b/Assets/FishNet/Plugins/Edgegap/Dependencies.meta new file mode 100644 index 00000000..1a9b9185 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Dependencies.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 14024ce6d2e64d5ba58ab20409ac648f +timeCreated: 1701785018 \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs new file mode 100644 index 00000000..6c4b15d4 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs @@ -0,0 +1,704 @@ +// MIRROR CHANGE: drop in Codice.Utils HttpUtility subset to not depend on Unity's plastic scm package +// SOURCE: Unity Plastic SCM package + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Edgegap.Codice.Utils // MIRROR CHANGE: namespace Edgegap.* to not collide if anyone has Plastic SCM installed already +{ + public class HttpEncoder + { + private static char[] hexChars = "0123456789abcdef".ToCharArray(); + private static object entitiesLock = new object(); + private static SortedDictionary entities; + private static HttpEncoder defaultEncoder = new HttpEncoder(); + private static HttpEncoder currentEncoder = HttpEncoder.defaultEncoder; + + private static IDictionary Entities + { + get + { + lock (HttpEncoder.entitiesLock) + { + if (HttpEncoder.entities == null) + HttpEncoder.InitEntities(); + return (IDictionary) HttpEncoder.entities; + } + } + } + + public static HttpEncoder Current + { + get => HttpEncoder.currentEncoder; + set => HttpEncoder.currentEncoder = value != null ? value : throw new ArgumentNullException(nameof (value)); + } + + public static HttpEncoder Default => HttpEncoder.defaultEncoder; + + protected internal virtual void HeaderNameValueEncode( + string headerName, + string headerValue, + out string encodedHeaderName, + out string encodedHeaderValue) + { + encodedHeaderName = !string.IsNullOrEmpty(headerName) ? HttpEncoder.EncodeHeaderString(headerName) : headerName; + if (string.IsNullOrEmpty(headerValue)) + encodedHeaderValue = headerValue; + else + encodedHeaderValue = HttpEncoder.EncodeHeaderString(headerValue); + } + + private static void StringBuilderAppend(string s, ref StringBuilder sb) + { + if (sb == null) + sb = new StringBuilder(s); + else + sb.Append(s); + } + + private static string EncodeHeaderString(string input) + { + StringBuilder sb = (StringBuilder) null; + for (int index = 0; index < input.Length; ++index) + { + char ch = input[index]; + if (ch < ' ' && ch != '\t' || ch == '\u007F') + HttpEncoder.StringBuilderAppend(string.Format("%{0:x2}", (object) (int) ch), ref sb); + } + return sb != null ? sb.ToString() : input; + } + + protected internal virtual void HtmlAttributeEncode(string value, TextWriter output) + { + if (output == null) + throw new ArgumentNullException(nameof (output)); + if (string.IsNullOrEmpty(value)) + return; + output.Write(HttpEncoder.HtmlAttributeEncode(value)); + } + + protected internal virtual void HtmlDecode(string value, TextWriter output) + { + if (output == null) + throw new ArgumentNullException(nameof (output)); + output.Write(HttpEncoder.HtmlDecode(value)); + } + + protected internal virtual void HtmlEncode(string value, TextWriter output) + { + if (output == null) + throw new ArgumentNullException(nameof (output)); + output.Write(HttpEncoder.HtmlEncode(value)); + } + + protected internal virtual byte[] UrlEncode(byte[] bytes, int offset, int count) => HttpEncoder.UrlEncodeToBytes(bytes, offset, count); + + protected internal virtual string UrlPathEncode(string value) + { + if (string.IsNullOrEmpty(value)) + return value; + MemoryStream result = new MemoryStream(); + int length = value.Length; + for (int index = 0; index < length; ++index) + HttpEncoder.UrlPathEncodeChar(value[index], (Stream) result); + return Encoding.ASCII.GetString(result.ToArray()); + } + + internal static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) + { + int num1 = bytes != null ? bytes.Length : throw new ArgumentNullException(nameof (bytes)); + if (num1 == 0) + return new byte[0]; + if (offset < 0 || offset >= num1) + throw new ArgumentOutOfRangeException(nameof (offset)); + if (count < 0 || count > num1 - offset) + throw new ArgumentOutOfRangeException(nameof (count)); + MemoryStream result = new MemoryStream(count); + int num2 = offset + count; + for (int index = offset; index < num2; ++index) + HttpEncoder.UrlEncodeChar((char) bytes[index], (Stream) result, false); + return result.ToArray(); + } + + internal static string HtmlEncode(string s) + { + switch (s) + { + case "": + return string.Empty; + case null: + return (string) null; + default: + bool flag = false; + for (int index = 0; index < s.Length; ++index) + { + char ch = s[index]; + if (ch == '&' || ch == '"' || ch == '<' || ch == '>' || ch > '\u009F' || ch == '\'') + { + flag = true; + break; + } + } + if (!flag) + return s; + StringBuilder stringBuilder = new StringBuilder(); + int length = s.Length; + for (int index = 0; index < length; ++index) + { + char ch = s[index]; + switch (ch) + { + case '"': + stringBuilder.Append("""); + break; + case '&': + stringBuilder.Append("&"); + break; + case '\'': + stringBuilder.Append("'"); + break; + case '<': + stringBuilder.Append("<"); + break; + case '>': + stringBuilder.Append(">"); + break; + case '<': + stringBuilder.Append("<"); + break; + case '>': + stringBuilder.Append(">"); + break; + default: + if (ch > '\u009F' && ch < 'Ā') + { + stringBuilder.Append("&#"); + stringBuilder.Append(((int) ch).ToString((IFormatProvider) CultureInfo.InvariantCulture)); + stringBuilder.Append(";"); + break; + } + stringBuilder.Append(ch); + break; + } + } + return stringBuilder.ToString(); + } + } + + internal static string HtmlAttributeEncode(string s) + { + if (string.IsNullOrEmpty(s)) + return string.Empty; + bool flag = false; + for (int index = 0; index < s.Length; ++index) + { + char ch = s[index]; + int num; + switch (ch) + { + case '"': + case '&': + case '<': + num = 0; + break; + default: + num = ch != '\'' ? 1 : 0; + break; + } + if (num == 0) + { + flag = true; + break; + } + } + if (!flag) + return s; + StringBuilder stringBuilder = new StringBuilder(); + int length = s.Length; + for (int index = 0; index < length; ++index) + { + char ch = s[index]; + switch (ch) + { + case '"': + stringBuilder.Append("""); + break; + case '&': + stringBuilder.Append("&"); + break; + case '\'': + stringBuilder.Append("'"); + break; + case '<': + stringBuilder.Append("<"); + break; + default: + stringBuilder.Append(ch); + break; + } + } + return stringBuilder.ToString(); + } + + internal static string HtmlDecode(string s) + { + switch (s) + { + case "": + return string.Empty; + case null: + return (string) null; + default: + if (s.IndexOf('&') == -1) + return s; + StringBuilder stringBuilder1 = new StringBuilder(); + StringBuilder stringBuilder2 = new StringBuilder(); + StringBuilder stringBuilder3 = new StringBuilder(); + int length = s.Length; + int num1 = 0; + int num2 = 0; + bool flag1 = false; + bool flag2 = false; + for (int index = 0; index < length; ++index) + { + char ch = s[index]; + if (num1 == 0) + { + if (ch == '&') + { + stringBuilder2.Append(ch); + stringBuilder1.Append(ch); + num1 = 1; + } + else + stringBuilder3.Append(ch); + } + else if (ch == '&') + { + num1 = 1; + if (flag2) + { + stringBuilder2.Append(num2.ToString((IFormatProvider) CultureInfo.InvariantCulture)); + flag2 = false; + } + stringBuilder3.Append(stringBuilder2.ToString()); + stringBuilder2.Length = 0; + stringBuilder2.Append('&'); + } + else + { + switch (num1) + { + case 1: + if (ch == ';') + { + num1 = 0; + stringBuilder3.Append(stringBuilder2.ToString()); + stringBuilder3.Append(ch); + stringBuilder2.Length = 0; + break; + } + num2 = 0; + flag1 = false; + num1 = ch == '#' ? 3 : 2; + stringBuilder2.Append(ch); + stringBuilder1.Append(ch); + break; + case 2: + stringBuilder2.Append(ch); + if (ch == ';') + { + string str = stringBuilder2.ToString(); + if (str.Length > 1 && HttpEncoder.Entities.ContainsKey(str.Substring(1, str.Length - 2))) + str = HttpEncoder.Entities[str.Substring(1, str.Length - 2)].ToString(); + stringBuilder3.Append(str); + num1 = 0; + stringBuilder2.Length = 0; + stringBuilder1.Length = 0; + break; + } + break; + case 3: + if (ch == ';') + { + if (num2 == 0) + stringBuilder3.Append(stringBuilder1.ToString() + ";"); + else if (num2 > (int) ushort.MaxValue) + { + stringBuilder3.Append("&#"); + stringBuilder3.Append(num2.ToString((IFormatProvider) CultureInfo.InvariantCulture)); + stringBuilder3.Append(";"); + } + else + stringBuilder3.Append((char) num2); + num1 = 0; + stringBuilder2.Length = 0; + stringBuilder1.Length = 0; + flag2 = false; + } + else if (flag1 && Uri.IsHexDigit(ch)) + { + num2 = num2 * 16 + Uri.FromHex(ch); + flag2 = true; + stringBuilder1.Append(ch); + } + else if (char.IsDigit(ch)) + { + num2 = num2 * 10 + ((int) ch - 48); + flag2 = true; + stringBuilder1.Append(ch); + } + else if (num2 == 0 && (ch == 'x' || ch == 'X')) + { + flag1 = true; + stringBuilder1.Append(ch); + } + else + { + num1 = 2; + if (flag2) + { + stringBuilder2.Append(num2.ToString((IFormatProvider) CultureInfo.InvariantCulture)); + flag2 = false; + } + stringBuilder2.Append(ch); + } + break; + } + } + } + if (stringBuilder2.Length > 0) + stringBuilder3.Append(stringBuilder2.ToString()); + else if (flag2) + stringBuilder3.Append(num2.ToString((IFormatProvider) CultureInfo.InvariantCulture)); + return stringBuilder3.ToString(); + } + } + + internal static bool NotEncoded(char c) => c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_'; + + internal static void UrlEncodeChar(char c, Stream result, bool isUnicode) + { + if (c > 'ÿ') + { + int num = (int) c; + result.WriteByte((byte) 37); + result.WriteByte((byte) 117); + int index1 = num >> 12; + result.WriteByte((byte) HttpEncoder.hexChars[index1]); + int index2 = num >> 8 & 15; + result.WriteByte((byte) HttpEncoder.hexChars[index2]); + int index3 = num >> 4 & 15; + result.WriteByte((byte) HttpEncoder.hexChars[index3]); + int index4 = num & 15; + result.WriteByte((byte) HttpEncoder.hexChars[index4]); + } + else if (c > ' ' && HttpEncoder.NotEncoded(c)) + result.WriteByte((byte) c); + else if (c == ' ') + result.WriteByte((byte) 43); + else if (c < '0' || c < 'A' && c > '9' || c > 'Z' && c < 'a' || c > 'z') + { + if (isUnicode && c > '\u007F') + { + result.WriteByte((byte) 37); + result.WriteByte((byte) 117); + result.WriteByte((byte) 48); + result.WriteByte((byte) 48); + } + else + result.WriteByte((byte) 37); + int index5 = (int) c >> 4; + result.WriteByte((byte) HttpEncoder.hexChars[index5]); + int index6 = (int) c & 15; + result.WriteByte((byte) HttpEncoder.hexChars[index6]); + } + else + result.WriteByte((byte) c); + } + + internal static void UrlPathEncodeChar(char c, Stream result) + { + if (c < '!' || c > '~') + { + byte[] bytes = Encoding.UTF8.GetBytes(c.ToString()); + for (int index1 = 0; index1 < bytes.Length; ++index1) + { + result.WriteByte((byte) 37); + int index2 = (int) bytes[index1] >> 4; + result.WriteByte((byte) HttpEncoder.hexChars[index2]); + int index3 = (int) bytes[index1] & 15; + result.WriteByte((byte) HttpEncoder.hexChars[index3]); + } + } + else if (c == ' ') + { + result.WriteByte((byte) 37); + result.WriteByte((byte) 50); + result.WriteByte((byte) 48); + } + else + result.WriteByte((byte) c); + } + + private static void InitEntities() + { + HttpEncoder.entities = new SortedDictionary((IComparer) StringComparer.Ordinal); + HttpEncoder.entities.Add("nbsp", ' '); + HttpEncoder.entities.Add("iexcl", '¡'); + HttpEncoder.entities.Add("cent", '¢'); + HttpEncoder.entities.Add("pound", '£'); + HttpEncoder.entities.Add("curren", '¤'); + HttpEncoder.entities.Add("yen", '¥'); + HttpEncoder.entities.Add("brvbar", '¦'); + HttpEncoder.entities.Add("sect", '§'); + HttpEncoder.entities.Add("uml", '¨'); + HttpEncoder.entities.Add("copy", '©'); + HttpEncoder.entities.Add("ordf", 'ª'); + HttpEncoder.entities.Add("laquo", '«'); + HttpEncoder.entities.Add("not", '¬'); + HttpEncoder.entities.Add("shy", '\u00AD'); + HttpEncoder.entities.Add("reg", '®'); + HttpEncoder.entities.Add("macr", '¯'); + HttpEncoder.entities.Add("deg", '°'); + HttpEncoder.entities.Add("plusmn", '±'); + HttpEncoder.entities.Add("sup2", '\u00B2'); + HttpEncoder.entities.Add("sup3", '\u00B3'); + HttpEncoder.entities.Add("acute", '´'); + HttpEncoder.entities.Add("micro", 'µ'); + HttpEncoder.entities.Add("para", '¶'); + HttpEncoder.entities.Add("middot", '·'); + HttpEncoder.entities.Add("cedil", '¸'); + HttpEncoder.entities.Add("sup1", '\u00B9'); + HttpEncoder.entities.Add("ordm", 'º'); + HttpEncoder.entities.Add("raquo", '»'); + HttpEncoder.entities.Add("frac14", '\u00BC'); + HttpEncoder.entities.Add("frac12", '\u00BD'); + HttpEncoder.entities.Add("frac34", '\u00BE'); + HttpEncoder.entities.Add("iquest", '¿'); + HttpEncoder.entities.Add("Agrave", 'À'); + HttpEncoder.entities.Add("Aacute", 'Á'); + HttpEncoder.entities.Add("Acirc", 'Â'); + HttpEncoder.entities.Add("Atilde", 'Ã'); + HttpEncoder.entities.Add("Auml", 'Ä'); + HttpEncoder.entities.Add("Aring", 'Å'); + HttpEncoder.entities.Add("AElig", 'Æ'); + HttpEncoder.entities.Add("Ccedil", 'Ç'); + HttpEncoder.entities.Add("Egrave", 'È'); + HttpEncoder.entities.Add("Eacute", 'É'); + HttpEncoder.entities.Add("Ecirc", 'Ê'); + HttpEncoder.entities.Add("Euml", 'Ë'); + HttpEncoder.entities.Add("Igrave", 'Ì'); + HttpEncoder.entities.Add("Iacute", 'Í'); + HttpEncoder.entities.Add("Icirc", 'Î'); + HttpEncoder.entities.Add("Iuml", 'Ï'); + HttpEncoder.entities.Add("ETH", 'Ð'); + HttpEncoder.entities.Add("Ntilde", 'Ñ'); + HttpEncoder.entities.Add("Ograve", 'Ò'); + HttpEncoder.entities.Add("Oacute", 'Ó'); + HttpEncoder.entities.Add("Ocirc", 'Ô'); + HttpEncoder.entities.Add("Otilde", 'Õ'); + HttpEncoder.entities.Add("Ouml", 'Ö'); + HttpEncoder.entities.Add("times", '×'); + HttpEncoder.entities.Add("Oslash", 'Ø'); + HttpEncoder.entities.Add("Ugrave", 'Ù'); + HttpEncoder.entities.Add("Uacute", 'Ú'); + HttpEncoder.entities.Add("Ucirc", 'Û'); + HttpEncoder.entities.Add("Uuml", 'Ü'); + HttpEncoder.entities.Add("Yacute", 'Ý'); + HttpEncoder.entities.Add("THORN", 'Þ'); + HttpEncoder.entities.Add("szlig", 'ß'); + HttpEncoder.entities.Add("agrave", 'à'); + HttpEncoder.entities.Add("aacute", 'á'); + HttpEncoder.entities.Add("acirc", 'â'); + HttpEncoder.entities.Add("atilde", 'ã'); + HttpEncoder.entities.Add("auml", 'ä'); + HttpEncoder.entities.Add("aring", 'å'); + HttpEncoder.entities.Add("aelig", 'æ'); + HttpEncoder.entities.Add("ccedil", 'ç'); + HttpEncoder.entities.Add("egrave", 'è'); + HttpEncoder.entities.Add("eacute", 'é'); + HttpEncoder.entities.Add("ecirc", 'ê'); + HttpEncoder.entities.Add("euml", 'ë'); + HttpEncoder.entities.Add("igrave", 'ì'); + HttpEncoder.entities.Add("iacute", 'í'); + HttpEncoder.entities.Add("icirc", 'î'); + HttpEncoder.entities.Add("iuml", 'ï'); + HttpEncoder.entities.Add("eth", 'ð'); + HttpEncoder.entities.Add("ntilde", 'ñ'); + HttpEncoder.entities.Add("ograve", 'ò'); + HttpEncoder.entities.Add("oacute", 'ó'); + HttpEncoder.entities.Add("ocirc", 'ô'); + HttpEncoder.entities.Add("otilde", 'õ'); + HttpEncoder.entities.Add("ouml", 'ö'); + HttpEncoder.entities.Add("divide", '÷'); + HttpEncoder.entities.Add("oslash", 'ø'); + HttpEncoder.entities.Add("ugrave", 'ù'); + HttpEncoder.entities.Add("uacute", 'ú'); + HttpEncoder.entities.Add("ucirc", 'û'); + HttpEncoder.entities.Add("uuml", 'ü'); + HttpEncoder.entities.Add("yacute", 'ý'); + HttpEncoder.entities.Add("thorn", 'þ'); + HttpEncoder.entities.Add("yuml", 'ÿ'); + HttpEncoder.entities.Add("fnof", 'ƒ'); + HttpEncoder.entities.Add("Alpha", 'Α'); + HttpEncoder.entities.Add("Beta", 'Β'); + HttpEncoder.entities.Add("Gamma", 'Γ'); + HttpEncoder.entities.Add("Delta", 'Δ'); + HttpEncoder.entities.Add("Epsilon", 'Ε'); + HttpEncoder.entities.Add("Zeta", 'Ζ'); + HttpEncoder.entities.Add("Eta", 'Η'); + HttpEncoder.entities.Add("Theta", 'Θ'); + HttpEncoder.entities.Add("Iota", 'Ι'); + HttpEncoder.entities.Add("Kappa", 'Κ'); + HttpEncoder.entities.Add("Lambda", 'Λ'); + HttpEncoder.entities.Add("Mu", 'Μ'); + HttpEncoder.entities.Add("Nu", 'Ν'); + HttpEncoder.entities.Add("Xi", 'Ξ'); + HttpEncoder.entities.Add("Omicron", 'Ο'); + HttpEncoder.entities.Add("Pi", 'Π'); + HttpEncoder.entities.Add("Rho", 'Ρ'); + HttpEncoder.entities.Add("Sigma", 'Σ'); + HttpEncoder.entities.Add("Tau", 'Τ'); + HttpEncoder.entities.Add("Upsilon", 'Υ'); + HttpEncoder.entities.Add("Phi", 'Φ'); + HttpEncoder.entities.Add("Chi", 'Χ'); + HttpEncoder.entities.Add("Psi", 'Ψ'); + HttpEncoder.entities.Add("Omega", 'Ω'); + HttpEncoder.entities.Add("alpha", 'α'); + HttpEncoder.entities.Add("beta", 'β'); + HttpEncoder.entities.Add("gamma", 'γ'); + HttpEncoder.entities.Add("delta", 'δ'); + HttpEncoder.entities.Add("epsilon", 'ε'); + HttpEncoder.entities.Add("zeta", 'ζ'); + HttpEncoder.entities.Add("eta", 'η'); + HttpEncoder.entities.Add("theta", 'θ'); + HttpEncoder.entities.Add("iota", 'ι'); + HttpEncoder.entities.Add("kappa", 'κ'); + HttpEncoder.entities.Add("lambda", 'λ'); + HttpEncoder.entities.Add("mu", 'μ'); + HttpEncoder.entities.Add("nu", 'ν'); + HttpEncoder.entities.Add("xi", 'ξ'); + HttpEncoder.entities.Add("omicron", 'ο'); + HttpEncoder.entities.Add("pi", 'π'); + HttpEncoder.entities.Add("rho", 'ρ'); + HttpEncoder.entities.Add("sigmaf", 'ς'); + HttpEncoder.entities.Add("sigma", 'σ'); + HttpEncoder.entities.Add("tau", 'τ'); + HttpEncoder.entities.Add("upsilon", 'υ'); + HttpEncoder.entities.Add("phi", 'φ'); + HttpEncoder.entities.Add("chi", 'χ'); + HttpEncoder.entities.Add("psi", 'ψ'); + HttpEncoder.entities.Add("omega", 'ω'); + HttpEncoder.entities.Add("thetasym", 'ϑ'); + HttpEncoder.entities.Add("upsih", 'ϒ'); + HttpEncoder.entities.Add("piv", 'ϖ'); + HttpEncoder.entities.Add("bull", '•'); + HttpEncoder.entities.Add("hellip", '…'); + HttpEncoder.entities.Add("prime", '′'); + HttpEncoder.entities.Add("Prime", '″'); + HttpEncoder.entities.Add("oline", '‾'); + HttpEncoder.entities.Add("frasl", '⁄'); + HttpEncoder.entities.Add("weierp", '℘'); + HttpEncoder.entities.Add("image", 'ℑ'); + HttpEncoder.entities.Add("real", 'ℜ'); + HttpEncoder.entities.Add("trade", '™'); + HttpEncoder.entities.Add("alefsym", 'ℵ'); + HttpEncoder.entities.Add("larr", '←'); + HttpEncoder.entities.Add("uarr", '↑'); + HttpEncoder.entities.Add("rarr", '→'); + HttpEncoder.entities.Add("darr", '↓'); + HttpEncoder.entities.Add("harr", '↔'); + HttpEncoder.entities.Add("crarr", '↵'); + HttpEncoder.entities.Add("lArr", '⇐'); + HttpEncoder.entities.Add("uArr", '⇑'); + HttpEncoder.entities.Add("rArr", '⇒'); + HttpEncoder.entities.Add("dArr", '⇓'); + HttpEncoder.entities.Add("hArr", '⇔'); + HttpEncoder.entities.Add("forall", '∀'); + HttpEncoder.entities.Add("part", '∂'); + HttpEncoder.entities.Add("exist", '∃'); + HttpEncoder.entities.Add("empty", '∅'); + HttpEncoder.entities.Add("nabla", '∇'); + HttpEncoder.entities.Add("isin", '∈'); + HttpEncoder.entities.Add("notin", '∉'); + HttpEncoder.entities.Add("ni", '∋'); + HttpEncoder.entities.Add("prod", '∏'); + HttpEncoder.entities.Add("sum", '∑'); + HttpEncoder.entities.Add("minus", '−'); + HttpEncoder.entities.Add("lowast", '∗'); + HttpEncoder.entities.Add("radic", '√'); + HttpEncoder.entities.Add("prop", '∝'); + HttpEncoder.entities.Add("infin", '∞'); + HttpEncoder.entities.Add("ang", '∠'); + HttpEncoder.entities.Add("and", '∧'); + HttpEncoder.entities.Add("or", '∨'); + HttpEncoder.entities.Add("cap", '∩'); + HttpEncoder.entities.Add("cup", '∪'); + HttpEncoder.entities.Add("int", '∫'); + HttpEncoder.entities.Add("there4", '∴'); + HttpEncoder.entities.Add("sim", '∼'); + HttpEncoder.entities.Add("cong", '≅'); + HttpEncoder.entities.Add("asymp", '≈'); + HttpEncoder.entities.Add("ne", '≠'); + HttpEncoder.entities.Add("equiv", '≡'); + HttpEncoder.entities.Add("le", '≤'); + HttpEncoder.entities.Add("ge", '≥'); + HttpEncoder.entities.Add("sub", '⊂'); + HttpEncoder.entities.Add("sup", '⊃'); + HttpEncoder.entities.Add("nsub", '⊄'); + HttpEncoder.entities.Add("sube", '⊆'); + HttpEncoder.entities.Add("supe", '⊇'); + HttpEncoder.entities.Add("oplus", '⊕'); + HttpEncoder.entities.Add("otimes", '⊗'); + HttpEncoder.entities.Add("perp", '⊥'); + HttpEncoder.entities.Add("sdot", '⋅'); + HttpEncoder.entities.Add("lceil", '⌈'); + HttpEncoder.entities.Add("rceil", '⌉'); + HttpEncoder.entities.Add("lfloor", '⌊'); + HttpEncoder.entities.Add("rfloor", '⌋'); + HttpEncoder.entities.Add("lang", '〈'); + HttpEncoder.entities.Add("rang", '〉'); + HttpEncoder.entities.Add("loz", '◊'); + HttpEncoder.entities.Add("spades", '♠'); + HttpEncoder.entities.Add("clubs", '♣'); + HttpEncoder.entities.Add("hearts", '♥'); + HttpEncoder.entities.Add("diams", '♦'); + HttpEncoder.entities.Add("quot", '"'); + HttpEncoder.entities.Add("amp", '&'); + HttpEncoder.entities.Add("lt", '<'); + HttpEncoder.entities.Add("gt", '>'); + HttpEncoder.entities.Add("OElig", 'Œ'); + HttpEncoder.entities.Add("oelig", 'œ'); + HttpEncoder.entities.Add("Scaron", 'Š'); + HttpEncoder.entities.Add("scaron", 'š'); + HttpEncoder.entities.Add("Yuml", 'Ÿ'); + HttpEncoder.entities.Add("circ", 'ˆ'); + HttpEncoder.entities.Add("tilde", '˜'); + HttpEncoder.entities.Add("ensp", ' '); + HttpEncoder.entities.Add("emsp", ' '); + HttpEncoder.entities.Add("thinsp", ' '); + HttpEncoder.entities.Add("zwnj", '\u200C'); + HttpEncoder.entities.Add("zwj", '\u200D'); + HttpEncoder.entities.Add("lrm", '\u200E'); + HttpEncoder.entities.Add("rlm", '\u200F'); + HttpEncoder.entities.Add("ndash", '–'); + HttpEncoder.entities.Add("mdash", '—'); + HttpEncoder.entities.Add("lsquo", '‘'); + HttpEncoder.entities.Add("rsquo", '’'); + HttpEncoder.entities.Add("sbquo", '‚'); + HttpEncoder.entities.Add("ldquo", '“'); + HttpEncoder.entities.Add("rdquo", '”'); + HttpEncoder.entities.Add("bdquo", '„'); + HttpEncoder.entities.Add("dagger", '†'); + HttpEncoder.entities.Add("Dagger", '‡'); + HttpEncoder.entities.Add("permil", '‰'); + HttpEncoder.entities.Add("lsaquo", '‹'); + HttpEncoder.entities.Add("rsaquo", '›'); + HttpEncoder.entities.Add("euro", '€'); + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs.meta b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs.meta new file mode 100644 index 00000000..a7ba535f --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpEncoder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c9f699c227f48e381db521abe59c2e1 +timeCreated: 1701789490 \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs new file mode 100644 index 00000000..ea17c9e3 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs @@ -0,0 +1,230 @@ +// MIRROR CHANGE: drop in Codice.Utils HttpUtility subset to not depend on Unity's plastic scm package +// SOURCE: Unity Plastic SCM package + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Text; + +namespace Edgegap.Codice.Utils // MIRROR CHANGE: namespace Edgegap.* to not collide if anyone has Plastic SCM installed already +{ + public sealed class HttpUtility + { + private static void WriteCharBytes(IList buf, char ch, Encoding e) + { + if (ch > 'ÿ') + { + Encoding encoding = e; + char[] chars = new char[1]{ ch }; + foreach (byte num in encoding.GetBytes(chars)) + buf.Add((object) num); + } + else + buf.Add((object) (byte) ch); + } + + public static string UrlDecode(string s, Encoding e) + { + if (null == s) + return (string) null; + if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) + return s; + if (e == null) + e = Encoding.UTF8; + long length = (long) s.Length; + List buf = new List(); + for (int index = 0; (long) index < length; ++index) + { + char ch = s[index]; + if (ch == '%' && (long) (index + 2) < length && s[index + 1] != '%') + { + if (s[index + 1] == 'u' && (long) (index + 5) < length) + { + int num = HttpUtility.GetChar(s, index + 2, 4); + if (num != -1) + { + HttpUtility.WriteCharBytes((IList) buf, (char) num, e); + index += 5; + } + else + HttpUtility.WriteCharBytes((IList) buf, '%', e); + } + else + { + int num; + if ((num = HttpUtility.GetChar(s, index + 1, 2)) != -1) + { + HttpUtility.WriteCharBytes((IList) buf, (char) num, e); + index += 2; + } + else + HttpUtility.WriteCharBytes((IList) buf, '%', e); + } + } + else if (ch == '+') + HttpUtility.WriteCharBytes((IList) buf, ' ', e); + else + HttpUtility.WriteCharBytes((IList) buf, ch, e); + } + byte[] array = buf.ToArray(); + return e.GetString(array); + } + + private static int GetInt(byte b) + { + char ch = (char) b; + if (ch >= '0' && ch <= '9') + return (int) ch - 48; + if (ch >= 'a' && ch <= 'f') + return (int) ch - 97 + 10; + return ch >= 'A' && ch <= 'F' ? (int) ch - 65 + 10 : -1; + } + + private static int GetChar(string str, int offset, int length) + { + int num1 = 0; + int num2 = length + offset; + for (int index = offset; index < num2; ++index) + { + char b = str[index]; + if (b > '\u007F') + return -1; + int num3 = HttpUtility.GetInt((byte) b); + if (num3 == -1) + return -1; + num1 = (num1 << 4) + num3; + } + return num1; + } + + public static string UrlEncode(string str) => HttpUtility.UrlEncode(str, Encoding.UTF8); + + public static string UrlEncode(string s, Encoding Enc) + { + if (s == null) + return (string) null; + if (s == string.Empty) + return string.Empty; + bool flag = false; + int length = s.Length; + for (int index = 0; index < length; ++index) + { + char c = s[index]; + if ((c < '0' || c < 'A' && c > '9' || c > 'Z' && c < 'a' || c > 'z') && !HttpEncoder.NotEncoded(c)) + { + flag = true; + break; + } + } + if (!flag) + return s; + byte[] bytes1 = new byte[Enc.GetMaxByteCount(s.Length)]; + int bytes2 = Enc.GetBytes(s, 0, s.Length, bytes1, 0); + return Encoding.ASCII.GetString(HttpUtility.UrlEncodeToBytes(bytes1, 0, bytes2)); + } + + public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) => bytes == null ? (byte[]) null : HttpEncoder.Current.UrlEncode(bytes, offset, count); + + public static string HtmlDecode(string s) + { + if (s == null) + return (string) null; + using (StringWriter output = new StringWriter()) + { + HttpEncoder.Current.HtmlDecode(s, (TextWriter) output); + return output.ToString(); + } + } + + public static NameValueCollection ParseQueryString(string query) => HttpUtility.ParseQueryString(query, Encoding.UTF8); + + public static NameValueCollection ParseQueryString( + string query, + Encoding encoding) + { + if (query == null) + throw new ArgumentNullException(nameof (query)); + if (encoding == null) + throw new ArgumentNullException(nameof (encoding)); + if (query.Length == 0 || query.Length == 1 && query[0] == '?') + return (NameValueCollection) new HttpUtility.HttpQSCollection(); + if (query[0] == '?') + query = query.Substring(1); + NameValueCollection result = (NameValueCollection) new HttpUtility.HttpQSCollection(); + HttpUtility.ParseQueryString(query, encoding, result); + return result; + } + + internal static void ParseQueryString( + string query, + Encoding encoding, + NameValueCollection result) + { + if (query.Length == 0) + return; + string str1 = HttpUtility.HtmlDecode(query); + int length = str1.Length; + int num1 = 0; + bool flag = true; + while (num1 <= length) + { + int startIndex = -1; + int num2 = -1; + for (int index = num1; index < length; ++index) + { + if (startIndex == -1 && str1[index] == '=') + startIndex = index + 1; + else if (str1[index] == '&') + { + num2 = index; + break; + } + } + if (flag) + { + flag = false; + if (str1[num1] == '?') + ++num1; + } + string name; + if (startIndex == -1) + { + name = (string) null; + startIndex = num1; + } + else + name = HttpUtility.UrlDecode(str1.Substring(num1, startIndex - num1 - 1), encoding); + if (num2 < 0) + { + num1 = -1; + num2 = str1.Length; + } + else + num1 = num2 + 1; + string str2 = HttpUtility.UrlDecode(str1.Substring(startIndex, num2 - startIndex), encoding); + result.Add(name, str2); + if (num1 == -1) + break; + } + } + + private sealed class HttpQSCollection : NameValueCollection + { + public override string ToString() + { + int count = this.Count; + if (count == 0) + return ""; + StringBuilder stringBuilder = new StringBuilder(); + string[] allKeys = this.AllKeys; + for (int index = 0; index < count; ++index) + stringBuilder.AppendFormat("{0}={1}&", (object) allKeys[index], (object) HttpUtility.UrlEncode(this[allKeys[index]])); + if (stringBuilder.Length > 0) + --stringBuilder.Length; + return stringBuilder.ToString(); + } + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs.meta b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs.meta new file mode 100644 index 00000000..578640eb --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Dependencies/HttpUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f83f468a8b546fd92606db56038f9e6 +timeCreated: 1701785025 \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Editor.meta b/Assets/FishNet/Plugins/Edgegap/Editor.meta new file mode 100644 index 00000000..e5593273 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 635b395f47dc9f742b4d71144921bb0d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api.meta new file mode 100644 index 00000000..bb66b470 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d2a4589d6738cb4b82bb1ceebd1453f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs new file mode 100644 index 00000000..fd049018 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs @@ -0,0 +1,280 @@ +using System; +using System.Collections.Specialized; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +// using Codice.Utils; // MIRROR CHANGE +using Edgegap.Codice.Utils; // MIRROR CHANGE +using UnityEngine; + +namespace Edgegap.Editor.Api +{ + /// + /// Handles base URL and common methods for all Edgegap APIs. + /// + public abstract class EdgegapApiBase + { + #region Vars + private readonly HttpClient _httpClient = new HttpClient(); // Base address set // MIRROR CHANGE: Unity 2020 support + protected ApiEnvironment SelectedApiEnvironment { get; } + protected EdgegapWindowMetadata.LogLevel LogLevel { get; set; } + protected bool IsLogLevelDebug => LogLevel == EdgegapWindowMetadata.LogLevel.Debug; + + /// Based on SelectedApiEnvironment. + /// + private string GetBaseUrl() => + SelectedApiEnvironment == ApiEnvironment.Staging + ? ApiEnvironment.Staging.GetApiUrl() + : ApiEnvironment.Console.GetApiUrl(); + #endregion // Vars + + + /// "console" || "staging-console"? + /// Without the "token " prefix, although we'll clear this if present + /// You may want more-verbose logs other than errs + protected EdgegapApiBase( + ApiEnvironment apiEnvironment, + string apiToken, + EdgegapWindowMetadata.LogLevel logLevel = EdgegapWindowMetadata.LogLevel.Error) + { + this.SelectedApiEnvironment = apiEnvironment; + + this._httpClient.BaseAddress = new Uri($"{GetBaseUrl()}/"); + this._httpClient.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + string cleanedApiToken = apiToken.Replace("token ", ""); // We already prefixed token below + this._httpClient.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("token", cleanedApiToken); + + this.LogLevel = logLevel; + } + + + #region HTTP Requests + /// + /// POST | We already added "https://api.edgegap.com/" (or similar) BaseAddress via constructor. + /// + /// + /// Serialize to your model via Newtonsoft + /// + /// - Success => returns HttpResponseMessage result + /// - Error => Catches errs => returns null (no rethrow) + /// + protected async Task PostAsync(string relativePath = "", string json = "{}") + { + StringContent stringContent = CreateStringContent(json); + Uri uri = new Uri(_httpClient.BaseAddress, relativePath); // Normalize POST uri: Can't end with `/`. + + if (IsLogLevelDebug) + Debug.Log($"PostAsync to: `{uri}` with json: `{json}`"); + + try + { + return await ExecuteRequestAsync(() => _httpClient.PostAsync(uri, stringContent)); + } + catch (Exception e) + { + Debug.LogError($"Error: {e}"); + throw; + } + } + + /// + /// PATCH | We already added "https://api.edgegap.com/" (or similar) BaseAddress via constructor. + /// + /// + /// Serialize to your model via Newtonsoft + /// + /// - Success => returns HttpResponseMessage result + /// - Error => Catches errs => returns null (no rethrow) + /// + protected async Task PatchAsync(string relativePath = "", string json = "{}") + { + StringContent stringContent = CreateStringContent(json); + Uri uri = new Uri(_httpClient.BaseAddress, relativePath); // Normalize PATCH uri: Can't end with `/`. + + if (IsLogLevelDebug) + Debug.Log($"PatchAsync to: `{uri}` with json: `{json}`"); + + // (!) As of 11/15/2023, .PatchAsync() is "unsupported by Unity" -- so we manually set the verb and SendAsync() + // Create the request manually + HttpRequestMessage patchRequest = new HttpRequestMessage(new HttpMethod("PATCH"), uri) + { + Content = stringContent, + }; + + try + { + return await ExecuteRequestAsync(() => _httpClient.SendAsync(patchRequest)); + } + catch (Exception e) + { + Debug.LogError($"Error: {e}"); + throw; + } + } + + /// + /// GET | We already added "https://api.edgegap.com/" (or similar) BaseAddress via constructor. + /// + /// + /// + /// To append to the URL; eg: "foo=0&bar=1" + /// (!) First query key should prefix nothing, as shown + /// + /// - Success => returns HttpResponseMessage result + /// - Error => Catches errs => returns null (no rethrow) + /// + protected async Task GetAsync(string relativePath = "", string customQuery = "") + { + string completeRelativeUri = prepareEdgegapUriWithQuery( + relativePath, + customQuery); + + if (IsLogLevelDebug) + Debug.Log($"GetAsync to: `{completeRelativeUri} with customQuery: `{customQuery}`"); + + try + { + return await ExecuteRequestAsync(() => _httpClient.GetAsync(completeRelativeUri)); + } + catch (Exception e) + { + Debug.LogError($"Error: {e}"); + throw; + } + } + + /// + /// DELETE | We already added "https://api.edgegap.com/" (or similar) BaseAddress via constructor. + /// + /// + /// + /// To append to the URL; eg: "foo=0&bar=1" + /// (!) First query key should prefix nothing, as shown + /// + /// - Success => returns HttpResponseMessage result + /// - Error => Catches errs => returns null (no rethrow) + /// + protected async Task DeleteAsync(string relativePath = "", string customQuery = "") + { + string completeRelativeUri = prepareEdgegapUriWithQuery( + relativePath, + customQuery); + + if (IsLogLevelDebug) + Debug.Log($"DeleteAsync to: `{completeRelativeUri} with customQuery: `{customQuery}`"); + + try + { + return await ExecuteRequestAsync(() => _httpClient.DeleteAsync(completeRelativeUri)); + } + catch (Exception e) + { + Debug.LogError($"Error: {e}"); + throw; + } + } + + /// POST || GET + /// + /// + /// + private static async Task ExecuteRequestAsync( + Func> requestFunc, + CancellationToken cancellationToken = default) + { + HttpResponseMessage response = null; + try + { + response = await requestFunc(); + } + catch (HttpRequestException e) + { + Debug.LogError($"HttpRequestException: {e.Message}"); + return null; + } + catch (TaskCanceledException e) + { + if (cancellationToken.IsCancellationRequested) + Debug.LogError("Task was cancelled by caller."); + else + Debug.LogError($"TaskCanceledException: Timeout - {e.Message}"); + return null; + } + catch (Exception e) // Generic exception handler + { + Debug.LogError($"Unexpected error occurred: {e.Message}"); + return null; + } + + // Check for a successful status code + if (response == null) + { + Debug.Log("!Success (null response) - returning 500"); + return CreateUnknown500Err(); + } + + if (!response.IsSuccessStatusCode) + { + HttpMethod httpMethod = response.RequestMessage.Method; + Debug.Log($"!Success: {(short)response.StatusCode} {response.ReasonPhrase} - " + + $"{httpMethod} | {response.RequestMessage.RequestUri}` - " + + $"{response.Content?.ReadAsStringAsync().Result}"); + } + + return response; + } + #endregion // HTTP Requests + + + #region Utils + /// Creates a UTF-8 encoded application/json + json obj + /// Arbitrary json obj + /// + private StringContent CreateStringContent(string json = "{}") => + new StringContent(json, Encoding.UTF8, "application/json"); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + private static HttpResponseMessage CreateUnknown500Err() => + new HttpResponseMessage(HttpStatusCode.InternalServerError); // 500 - Unknown // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + /// + /// Merges Edgegap-required query params (source) -> merges with custom query -> normalizes. + /// + /// + /// + /// + private string prepareEdgegapUriWithQuery(string relativePath, string customQuery) + { + // Create UriBuilder using the BaseAddress + UriBuilder uriBuilder = new UriBuilder(_httpClient.BaseAddress); + + // Add the relative path to the UriBuilder's path + uriBuilder.Path += relativePath; + + // Parse the existing query from the UriBuilder + NameValueCollection query = HttpUtility.ParseQueryString(uriBuilder.Query); + + // Add default "source=unity" param + query["source"] = "unity"; + + // Parse and merge the custom query parameters + NameValueCollection customParams = HttpUtility.ParseQueryString(customQuery); + foreach (string key in customParams) + { + query[key] = customParams[key]; + } + + // Set the merged query back to the UriBuilder + uriBuilder.Query = query.ToString(); + + // Extract the complete relative URI and return it + return uriBuilder.Uri.PathAndQuery; + } + #endregion // Utils + } +} diff --git a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs.meta similarity index 83% rename from Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs.meta rename to Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs.meta index beb01e75..735b9236 100644 --- a/Assets/FishNet/Demos/Prediction V2 (Experimental)/Rigidbody/Scripts/SpringBoard/SpringBoard.cs.meta +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapApiBase.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 026366ce57064ab429b976f32c179b40 +guid: 50379f30f5137224aa05a5c7b6b5ebba MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs new file mode 100644 index 00000000..4e7eab14 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs @@ -0,0 +1,148 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Edgegap.Editor.Api.Models.Requests; +using Edgegap.Editor.Api.Models.Results; + +namespace Edgegap.Editor.Api +{ + /// + /// Wraps the v1/app API endpoint: Applications Control API. + /// - API Doc | https://docs.edgegap.com/api/#tag/Applications + /// + public class EdgegapAppApi : EdgegapApiBase + { + public EdgegapAppApi( + ApiEnvironment apiEnvironment, + string apiToken, + EdgegapWindowMetadata.LogLevel logLevel = EdgegapWindowMetadata.LogLevel.Error) + : base(apiEnvironment, apiToken, logLevel) + { + } + + + #region API Methods + /// + /// POST to v1/app + /// - Create an application that will regroup application versions. + /// - API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/application-post + /// + /// + /// Http info with GetCreateAppResult data model + /// - Success: 200 + /// - Fail: 409 (app already exists), 400 (reached limit) + /// + public async Task> CreateApp(CreateAppRequest request) + { + HttpResponseMessage response = await PostAsync("v1/app", request.ToString()); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + + /// + /// GET to v1/app + /// - Get an application that will regroup application versions. + /// - API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/application-post + /// + /// + /// Http info with GetCreateAppResult data model + /// - Success: 200 + /// + public async Task> GetApp(string appName) + { + HttpResponseMessage response = await GetAsync($"v1/app/{appName}"); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + + /// + /// PATCH to v1/app/{app_name}/version/{version_name} + /// - Update an *existing* application version with new specifications. + /// - API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-versions-patch + /// + /// + /// Http info with UpdateAppVersionRequest data model + /// - Success: 200 + /// + public async Task> UpdateAppVersion(UpdateAppVersionRequest request) + { + string relativePath = $"v1/app/{request.AppName}/version/{request.VersionName}"; + HttpResponseMessage response = await PatchAsync(relativePath, request.ToString()); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + + /// + /// POST to v1/app/{app_name}/version + /// - Create an new application version with new specifications. + /// - API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post + /// + /// + /// Http info with UpdateAppVersionRequest data model + /// - Success: 200 (no result model) + /// - Fail: 409 (app already exists), 400 (reached limit) + /// + public async Task> CreateAppVersion(CreateAppVersionRequest request) + { + string relativePath = $"v1/app/{request.AppName}/version"; + HttpResponseMessage response = await PostAsync(relativePath, request.ToString()); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + + if (!isSuccess) + return result; + + return result; + } + #endregion // API Methods + + + #region Chained API Methods + /// + /// PATCH and/or POST to v1/app/: Upsert an *existing* application version with new specifications. + /// - Consumes either 1 or 2 API calls: 1st tries to PATCH, then POST if PATCH fails (!exists). + /// - API POST Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post + /// - API PATCH Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-versions-patch + /// + /// + /// Http info with UpdateAppVersionRequest data model + /// - Success: 200 (no result model) + /// - Fail: 409 (app already exists), 400 (reached limit) + /// + public async Task> UpsertAppVersion(UpdateAppVersionRequest request) + { + EdgegapHttpResult result = await UpdateAppVersion(request); // PATCH + + if (result.HasErr) + { + // Try to create, instead + CreateAppVersionRequest createAppVersionRequest = CreateAppVersionRequest.FromUpdateRequest(request); + result = await CreateAppVersion(createAppVersionRequest); // POST + } + + bool isSuccess = result.StatusCode == HttpStatusCode.OK; // 200 + + if (!isSuccess) + return result; + + return result; + } + #endregion // Chained API Methods + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs.meta new file mode 100644 index 00000000..7f217015 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapAppApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b0b3b865abe64b49a4000294c4e9593 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs new file mode 100644 index 00000000..dda3ce24 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs @@ -0,0 +1,177 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Edgegap.Editor.Api.Models.Requests; +using Edgegap.Editor.Api.Models.Results; +using UnityEngine.Assertions; + +namespace Edgegap.Editor.Api +{ + /// + /// Wraps the v1/[deploy | status | stop] API endpoints: Deployments Control API. + /// - API Doc | https://docs.edgegap.com/api/#tag/Deployments + /// + public class EdgegapDeploymentsApi : EdgegapApiBase + { + public EdgegapDeploymentsApi( + ApiEnvironment apiEnvironment, + string apiToken, + EdgegapWindowMetadata.LogLevel logLevel = EdgegapWindowMetadata.LogLevel.Error) + : base(apiEnvironment, apiToken, logLevel) + { + } + + + #region API Methods + /// + /// POST v1/deploy + /// - Create a new deployment. Deployment is a server instance of your application version. + /// - API Doc | https://docs.edgegap.com/api/#tag/Deployments + /// + /// + /// Http info with CreateDeploymentResult data model + /// - Success: 200 + /// + public async Task> CreateDeploymentAsync( + CreateDeploymentRequest request) + { + HttpResponseMessage response = await PostAsync("v1/deploy", request.ToString()); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + + /// + /// GET v1/status/{requestId} + /// - Retrieve the information for a deployment. + /// - API Doc | https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-status-get + /// + /// + /// Unique Identifier to keep track of your request across all Arbitrium ecosystem. + /// It's included in the response of the app deploy. Ex: "93924761ccde" + /// + /// Http info with GetDeploymentStatusResult data model + /// - Success: 200 + /// + public async Task> GetDeploymentStatusAsync(string requestId) + { + HttpResponseMessage response = await GetAsync($"v1/status/{requestId}"); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + + /// + /// DELETE v1/stop/{requestId} + /// - Delete an instance of deployment. It will stop the running container and all its games. + /// - API Doc | https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-status-get + /// + /// + /// Unique Identifier to keep track of your request across all Arbitrium ecosystem. + /// It's included in the response of the app deploy. Ex: "93924761ccde" + /// + /// Http info with GetDeploymentStatusResult data model + /// - Success: 200 + /// + public async Task> StopActiveDeploymentAsync(string requestId) + { + HttpResponseMessage response = await DeleteAsync($"v1/stop/{requestId}"); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + #endregion // API Methods + + + #region Chained API Methods + /// + /// POST v1/deploy => GET v1/status/{requestId} + /// - Create a new deployment. Deployment is a server instance of your application version. + /// - Then => await READY status. + /// - API Doc | https://docs.edgegap.com/api/#tag/Deployments + /// + /// + /// Http info with CreateDeploymentResult data model (with a READY deployment status) + /// - Success: 200 + /// - Error: If createResult.HasErr, returns createResult + /// + public async Task> CreateDeploymentAwaitReadyStatusAsync( + CreateDeploymentRequest request, TimeSpan pollInterval) + { + EdgegapHttpResult createResponse = await CreateDeploymentAsync(request); + + // Create => + bool isCreateSuccess = createResponse.StatusCode == HttpStatusCode.OK; // 200 + if (!isCreateSuccess) + return createResponse; + + // Await Status READY => + string requestId = createResponse.Data.RequestId; + _ = await AwaitReadyStatusAsync(requestId, pollInterval); + + // Return no matter what the result; no need to validate + return createResponse; + } + + /// If you recently deployed but want to await READY status. + /// + /// + public async Task> AwaitReadyStatusAsync( + string requestId, + TimeSpan pollInterval) + { + Assert.IsTrue(!string.IsNullOrEmpty(requestId)); // Validate + + EdgegapHttpResult statusResponse = null; + CancellationTokenSource cts = new CancellationTokenSource (TimeSpan.FromMinutes( // MIRROR CHANGE: 'new()' not supported in Unity 2020 + EdgegapWindowMetadata.DEPLOYMENT_AWAIT_READY_STATUS_TIMEOUT_MINS)); + bool isReady = false; + + while (!isReady && !cts.Token.IsCancellationRequested) + { + await Task.Delay(pollInterval, cts.Token); + statusResponse = await GetDeploymentStatusAsync(requestId); + isReady = statusResponse.Data.CurrentStatus == EdgegapWindowMetadata.READY_STATUS; + } + + return statusResponse; + } + + /// If you recently stopped a deployment, but want to await TERMINATED (410) status. + /// + /// + public async Task> AwaitTerminatedDeleteStatusAsync( + string requestId, + TimeSpan pollInterval) + { + EdgegapHttpResult deleteResponse = null; + CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMinutes( // MIRROR CHANGE: 'new()' not supported in Unity 2020 + EdgegapWindowMetadata.DEPLOYMENT_AWAIT_READY_STATUS_TIMEOUT_MINS)); + bool isStopped = false; + + while (!isStopped && !cts.Token.IsCancellationRequested) + { + await Task.Delay(pollInterval, cts.Token); + deleteResponse = await StopActiveDeploymentAsync(requestId); + isStopped = deleteResponse.StatusCode == HttpStatusCode.Gone; // 410 + } + + return deleteResponse; + } + #endregion Chained API Methods + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs.meta new file mode 100644 index 00000000..08f9b346 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapDeploymentsApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37ecdc6abda4402419438f2284ef2d95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs new file mode 100644 index 00000000..86e4b26a --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs @@ -0,0 +1,47 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Edgegap.Editor.Api.Models.Results; + +namespace Edgegap.Editor.Api +{ + /// + /// Wraps the v1/ip API endpoint: "IP Lookup" API. + /// - API Doc | https://docs.edgegap.com/api/#tag/IP-Lookup + /// + public class EdgegapIpApi : EdgegapApiBase + { + public EdgegapIpApi( + ApiEnvironment apiEnvironment, + string apiToken, + EdgegapWindowMetadata.LogLevel logLevel = EdgegapWindowMetadata.LogLevel.Error) + : base(apiEnvironment, apiToken, logLevel) + { + } + + + #region API Methods + /// + /// GET to v1/app + /// - Retrieve your public IP address. + /// - API Doc | https://docs.edgegap.com/api/#tag/IP-Lookup/operation/IP + /// + /// + /// Http info with GetCreateAppResult data model + /// - Success: 200 + /// - Fail: 409 (app already exists), 400 (reached limit) + /// + public async Task> GetYourPublicIp() + { + HttpResponseMessage response = await GetAsync("v1/ip"); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + bool isSuccess = response.StatusCode == HttpStatusCode.OK; // 200 + if (!isSuccess) + return result; + + return result; + } + #endregion // API Methods + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs.meta new file mode 100644 index 00000000..fa966ab9 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapIpApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fac4a7425623f39488af09d60549313e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs new file mode 100644 index 00000000..5d4a25ff --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs @@ -0,0 +1,52 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Edgegap.Editor.Api.Models.Results; +using Newtonsoft.Json.Linq; + +namespace Edgegap.Editor.Api +{ + /// Wraps the v1/wizard API endpoint. Used for internal purposes. + public class EdgegapWizardApi : EdgegapApiBase + { + /// Extended path after the base uri + public EdgegapWizardApi( + ApiEnvironment apiEnvironment, + string apiToken, + EdgegapWindowMetadata.LogLevel logLevel = EdgegapWindowMetadata.LogLevel.Error) + : base(apiEnvironment, apiToken, logLevel) + { + } + + + #region API Methods + /// POST to v1/wizard/init-quick-start + /// + /// Http info with no explicit data model + /// - Success: 204 (no result model) + /// + public async Task InitQuickStart() + { + string json = new JObject { ["source"] = "unity" }.ToString(); + HttpResponseMessage response = await PostAsync("v1/wizard/init-quick-start", json); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + return result; + } + + /// GET to v1/wizard/registry-credentials + /// + /// - Http info with GetRegistryCredentialsResult data model + /// - Success: 200 + /// - Error: Likely if called before a successful InitQuickStart(), + /// or if called in a staging env. Soon, this will be available in production. + /// + public async Task> GetRegistryCredentials() + { + HttpResponseMessage response = await GetAsync("v1/wizard/registry-credentials"); + EdgegapHttpResult result = new EdgegapHttpResult(response); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + return result; + } + #endregion // API Methods + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs.meta new file mode 100644 index 00000000..5e167bec --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/EdgegapWizardApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6986ee67361f0b45928ccd70c7ab12c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models.meta new file mode 100644 index 00000000..2c5a7931 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aed107c714fce71449ef56590221c567 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs new file mode 100644 index 00000000..782bc7b1 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models +{ + /// + /// Used in `UpdateAppVersionRequest`, `CreateAppVersionRequest`. + /// For GetDeploymentStatusResult, see DeploymentPortsData + /// + public class AppPortsData + { + /// 1024~49151; Default 7770 + [JsonProperty("port")] + public int Port { get; set; } = EdgegapWindowMetadata.PORT_DEFAULT; + + /// Default "UDP" + [JsonProperty("protocol")] + public string ProtocolStr { get; set; } = EdgegapWindowMetadata.DEFAULT_PROTOCOL_TYPE.ToString(); + + [JsonProperty("to_check")] + public bool ToCheck { get; set; } = true; + + [JsonProperty("tls_upgrade")] + public bool TlsUpgrade { get; set; } + + [JsonProperty("name")] + public string PortName { get; set; } = "Game Port"; + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs.meta new file mode 100644 index 00000000..d7e6083c --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/AppPortsData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6d4864ea3706574fb35920c6fab46fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs new file mode 100644 index 00000000..972205b7 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models +{ + /// Used in `GetDeploymentStatus`. + public class DeploymentPortsData + { + [JsonProperty("external")] + public int External { get; set; } + + [JsonProperty("internal")] + public int Internal { get; set; } + + [JsonProperty("protocol")] + public string Protocol { get; set; } + + [JsonProperty("name")] + public string PortName { get; set; } + + [JsonProperty("tls_upgrade")] + public bool TlsUpgrade { get; set; } + + [JsonProperty("link")] + public string Link { get; set; } + + [JsonProperty("proxy")] + public int? Proxy { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs.meta new file mode 100644 index 00000000..0efdcc2c --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/DeploymentPortsData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 62d51b44b8414c9f968ca607ccb06b7e +timeCreated: 1701522748 \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs new file mode 100644 index 00000000..d9c89bb1 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models +{ + public class LocationData + { + [JsonProperty("city")] + public string City { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + + [JsonProperty("continent")] + public string Continent { get; set; } + + [JsonProperty("administrative_division")] + public string AdministrativeDivision { get; set; } + + [JsonProperty("timezone")] + public string Timezone { get; set; } + + [JsonProperty("latitude")] + public double Latitude { get; set; } + + [JsonProperty("longitude")] + public double Longitude { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs.meta new file mode 100644 index 00000000..c99e8018 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/LocationData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57eed0dbd556e074c992cf6599a1f6bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs new file mode 100644 index 00000000..d72086db --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs @@ -0,0 +1,18 @@ +namespace Edgegap.Editor.Api.Models +{ + /// + /// Unity default: UDP. + /// (!) UDP !works in WebGL. + /// + public enum ProtocolType + { + /// Unity default - fastest; !works in WebGL. + UDP, + + /// Slower, but more reliable; works in WebGL. + TCP, + + /// Slower, but more reliable; works in WebGL. + WS, + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs.meta new file mode 100644 index 00000000..06560580 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/ProtocolType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be5acd63e783b364ebdbb783639e2d32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests.meta new file mode 100644 index 00000000..bcd87e44 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1b2a5c481353934f906c30ba047df9b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs new file mode 100644 index 00000000..91e3c261 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Requests +{ + /// + /// Request model for https://docs.edgegap.com/api/#tag/Applications/operation/application-post + /// + public class CreateAppRequest + { + #region Required + /// *The application name. + [JsonProperty("name")] + public string AppName { get; set; } + #endregion // Required + + + #region Optional + /// *If the application can be deployed. + [JsonProperty("is_active")] + public bool IsActive { get; set; } + + /// *Image base64 string. + [JsonProperty("image")] + public string Image { get; set; } + + /// If the telemetry agent is installed on the versions of this app. + [JsonProperty("is_telemetry_agent_active")] + public bool IsTelemetryAgentActive { get; set; } + #endregion // Optional + + + /// Used by Newtonsoft + public CreateAppRequest() + { + } + + /// Init with required info + /// The application name + /// If the application can be deployed + /// Image base64 string + public CreateAppRequest( + string appName, + bool isActive, + string image) + { + this.AppName = appName; + this.IsActive = isActive; + this.Image = image; + } + + /// Parse to json str + public override string ToString() => + JsonConvert.SerializeObject(this); + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs.meta new file mode 100644 index 00000000..268be5cc --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a492d7c515b8894ea30b37db6b7efe4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs new file mode 100644 index 00000000..360ed43b --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs @@ -0,0 +1,225 @@ +using System; +using Newtonsoft.Json; +using UnityEngine; + +namespace Edgegap.Editor.Api.Models.Requests +{ + /// + /// Request model for `POST v1/app/{app_name}/version`. + /// API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post + /// + public class CreateAppVersionRequest + { + #region Required + /// *The name of the application associated. + [JsonIgnore] // *Path var + public string AppName { get; set; } + + /// *The name of the application associated. + [JsonProperty("name")] + public string VersionName { get; set; } = EdgegapWindowMetadata.DEFAULT_VERSION_TAG; + + /// *The tag of your image. Default == "latest". + /// "0.1.2" || "latest" (although "latest" !recommended; use actual versions in production) + [JsonProperty("docker_tag")] + public string DockerTag { get; set; } = EdgegapWindowMetadata.DEFAULT_VERSION_TAG; + + /// *The name of your image. + /// "edgegap/demo" || "myCompany-someId/mylowercaseapp" + [JsonProperty("docker_image")] + public string DockerImage { get; set; } = ""; + + /// *The Repository where the image is. + /// "registry.edgegap.com" || "harbor.edgegap.com" || "docker.io" + [JsonProperty("docker_repository")] + public string DockerRepository { get; set; } = ""; + + /// *Units of vCPU needed (1024 = 1vcpu) + [JsonProperty("req_cpu")] + public int ReqCpu { get; set; } = 256; + + /// *Units of memory in MB needed (1024 = 1 GPU) + [JsonProperty("req_memory")] + public int ReqMemory { get; set; } = 256; + + /// *Required: At least 1 { Port, ProtocolStr }. + [JsonProperty("ports")] + public AppPortsData[] Ports { get; set; } = {}; + + /// The username to access the docker repository + [JsonProperty("private_username")] + public string PrivateUsername { get; set; } = ""; + + /// The Private Password or Token of the username (We recommend to use a token) + [JsonProperty("private_token")] + public string PrivateToken { get; set; } = ""; + #endregion // Required + + + // #region Optional + // [JsonProperty("is_active")] + // public bool IsActive { get; set; } = true; + // + // [JsonProperty("req_video")] + // public int ReqVideo { get; set; } = 256; + // + // [JsonProperty("max_duration")] + // public int MaxDuration { get; set; } = 30; + // + // [JsonProperty("use_telemetry")] + // public bool UseTelemetry { get; set; } = true; + // + // [JsonProperty("inject_context_env")] + // public bool InjectContextEnv { get; set; } = true; + // + // [JsonProperty("whitelisting_active")] + // public bool WhitelistingActive { get; set; } = true; + // + // [JsonProperty("force_cache")] + // public bool ForceCache { get; set; } + // + // [JsonProperty("cache_min_hour")] + // public int CacheMinHour { get; set; } + // + // [JsonProperty("cache_max_hour")] + // public int CacheMaxHour { get; set; } + // + // [JsonProperty("time_to_deploy")] + // public int TimeToDeploy { get; set; } = 15; + // + // [JsonProperty("enable_all_locations")] + // public bool EnableAllLocations { get; set; } + // + // [JsonProperty("termination_grace_period_seconds")] + // public int TerminationGracePeriodSeconds { get; set; } = 5; + // + // [JsonProperty("endpoint_storage")] + // public string EndpointStorage { get; set; } = ""; + // + // [JsonProperty("command")] + // public string Command { get; set; } + // + // [JsonProperty("arguments")] + // public string Arguments { get; set; } + // + // [JsonProperty("verify_image")] + // public bool VerifyImage { get; set; } + // + // [JsonProperty("session_config")] + // public SessionConfigData SessionConfig { get; set; } = new(); + // + // [JsonProperty("probe")] + // public ProbeData Probe { get; set; } = new(); + // + // [JsonProperty("envs")] + // public EnvsData[] Envs { get; set; } = {}; + // + // public class SessionConfigData + // { + // [JsonProperty("kind")] + // public string Kind { get; set; } = "Seat"; + // + // [JsonProperty("sockets")] + // public int Sockets { get; set; } = 10; + // + // [JsonProperty("autodeploy")] + // public bool Autodeploy { get; set; } = true; + // + // [JsonProperty("empty_ttl")] + // public int EmptyTtl { get; set; } = 60; + // + // [JsonProperty("session_max_duration")] + // public int SessionMaxDuration { get; set; } = 60; + // } + // + // + // public class ProbeData + // { + // [JsonProperty("optimal_ping")] + // public int OptimalPing { get; set; } = 60; + // + // [JsonProperty("rejected_ping")] + // public int RejectedPing { get; set; } = 180; + // } + // + // public class EnvsData + // { + // [JsonProperty("key")] + // public string Key { get; set; } + // + // [JsonProperty("value")] + // public string Value { get; set; } + // + // [JsonProperty("is_secret")] + // public bool IsSecret { get; set; } = true; + // } + // #endregion // Optional + + /// Used by Newtonsoft + public CreateAppVersionRequest() + { + } + + /// + /// Init with required info. + /// (!) If looking for refs, also see FromUpdateRequest() builder below. + /// + /// The name of the application. + /// + /// + /// + /// + public CreateAppVersionRequest( + string appName, + string containerRegistryUsername, + string containerRegistryPasswordToken, + int portNum, + ProtocolType protocolType) + { + this.AppName = appName; + this.PrivateUsername = containerRegistryUsername; + this.PrivateToken = containerRegistryPasswordToken; + this.Ports = new AppPortsData[] + { + new AppPortsData() // MIRROR CHANGE: 'new()' not supported in Unity 2020 + { + Port = portNum, + ProtocolStr = protocolType.ToString(), + }, + }; + } + + /// + /// Port from Update PATCH model: If you tried to Update, but !exists, you probably want to create it next. + /// + /// + public static CreateAppVersionRequest FromUpdateRequest(UpdateAppVersionRequest updateRequest) + { + // Convert the updateRequest to JSON + string json = JsonConvert.SerializeObject(updateRequest); + + // Deserialize the JSON back to CreateAppVersionRequest + CreateAppVersionRequest createReq = null; + + try + { + createReq = JsonConvert.DeserializeObject(json); + createReq.AppName = updateRequest.AppName; // Normally JsonIgnored in Update + createReq.VersionName = updateRequest.VersionName; // Normally JsonIgnored in Update + createReq.PrivateUsername = updateRequest.PrivateUsername; + createReq.PrivateToken = updateRequest.PrivateToken; + } + catch (Exception e) + { + Debug.LogError($"Error (when parsing CreateAppVersionRequest from CreateAppVersionRequest): {e}"); + throw; + } + + return createReq; + } + + /// Parse to json str + public override string ToString() => + JsonConvert.SerializeObject(this); + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs.meta new file mode 100644 index 00000000..cf964e40 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateAppVersionRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb645e2f9d04384a85739269cc8a4e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs new file mode 100644 index 00000000..968821cc --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Requests +{ + /// + /// Request model for `POST v1/deploy`. + /// API Doc | https://docs.edgegap.com/api/#tag/Deployments/operation/deploy + /// + public class CreateDeploymentRequest + { + #region Required + /// *Required: The name of the App you want to deploy. + [JsonProperty("app_name")] + public string AppName { get; set; } + + /// + /// *Required: The name of the App Version you want to deploy; + /// if not present, the last version created is picked. + /// + [JsonProperty("version_name")] + public string VersionName { get; set; } + + /// + /// *Required: The List of IP of your user. + /// + [JsonProperty("ip_list")] + public string[] IpList { get; set; } + + /// + /// *Required: The list of IP of your user with their location (latitude, longitude). + /// + [JsonProperty("geo_ip_list")] + public string[] GeoIpList { get; set; } = {}; + #endregion // Required + + + /// Used by Newtonsoft + public CreateDeploymentRequest() + { + } + + /// Init with required info; used for a single external IP address. + /// The name of the application. + /// + /// The name of the App Version you want to deploy, if not present, + /// the last version created is picked. + /// + /// Obtain from IpApi. + public CreateDeploymentRequest( + string appName, + string versionName, + string externalIp) + { + this.AppName = appName; + this.VersionName = versionName; + this.IpList = new[] { externalIp }; + } + + /// Parse to json str + public override string ToString() => + JsonConvert.SerializeObject(this); + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs.meta new file mode 100644 index 00000000..3391cdd8 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/CreateDeploymentRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aae7b317093230e419bc0f8be1097ea6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs new file mode 100644 index 00000000..8a1d76b1 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs @@ -0,0 +1,175 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Requests +{ + /// + /// Request model for `PATCH v1/app/{app_name}/version/{version_name}`. + /// Request model for https://docs.edgegap.com/api/#tag/Applications/operation/app-versions-patch + /// TODO: Split "Create" and "Update" into their own, separate models: CTRL+F for "(!)" for more info. + /// + public class UpdateAppVersionRequest + { + #region Required + /// *Required: The name of the application. + [JsonIgnore] // *Path var + public string AppName { get; set; } + #endregion // Required + + + #region Optional + /// The name of the application version. + [JsonIgnore] // *Path var + public string VersionName { get; set; } = EdgegapWindowMetadata.DEFAULT_VERSION_TAG; + + /// At least 1 { Port, ProtocolStr } + [JsonProperty("ports")] + public AppPortsData[] Ports { get; set; } = {}; + + /// The Repository where the image is. + /// "registry.edgegap.com" || "harbor.edgegap.com" || "docker.io" + [JsonProperty("docker_repository")] + public string DockerRepository { get; set; } = ""; + + /// The name of your image. + /// "edgegap/demo" || "myCompany-someId/mylowercaseapp" + [JsonProperty("docker_image")] + public string DockerImage { get; set; } = ""; + + /// The tag of your image. Default == "latest". + /// "0.1.2" || "latest" (although "latest" !recommended; use actual versions in production) + [JsonProperty("docker_tag")] + public string DockerTag { get; set; } = EdgegapWindowMetadata.DEFAULT_VERSION_TAG; + + [JsonProperty("is_active")] + public bool IsActive { get; set; } = true; + + [JsonProperty("private_username")] + public string PrivateUsername { get; set; } = ""; + + [JsonProperty("private_token")] + public string PrivateToken { get; set; } = ""; + + #region (!) Shows in API docs for PATCH, but could be CREATE only? "Unknown Args" + // [JsonProperty("req_cpu")] + // public int ReqCpu { get; set; } = 256; + // + // [JsonProperty("req_memory")] + // public int ReqMemory { get; set; } = 256; + // + // [JsonProperty("req_video")] + // public int ReqVideo { get; set; } = 256; + #endregion // (!) Shows in API docs for PATCH, but could be CREATE only? "Unknown Args" + + [JsonProperty("max_duration")] + public int MaxDuration { get; set; } = 60; + + [JsonProperty("use_telemetry")] + public bool UseTelemetry { get; set; } = true; + + [JsonProperty("inject_context_env")] + public bool InjectContextEnv { get; set; } = true; + + [JsonProperty("whitelisting_active")] + public bool WhitelistingActive { get; set; } = false; + + [JsonProperty("force_cache")] + public bool ForceCache { get; set; } + + [JsonProperty("cache_min_hour")] + public int CacheMinHour { get; set; } + + [JsonProperty("cache_max_hour")] + public int CacheMaxHour { get; set; } + + [JsonProperty("time_to_deploy")] + public int TimeToDeploy { get; set; } = 120; + + [JsonProperty("enable_all_locations")] + public bool EnableAllLocations { get; set; } + + [JsonProperty("termination_grace_period_seconds")] + public int TerminationGracePeriodSeconds { get; set; } = 5; + + // // (!) BUG: Expects empty string "" at minimum; however, empty string will throw server err + // [JsonProperty("endpoint_storage")] + // public string EndpointStorage { get; set; } + + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("arguments")] + public string Arguments { get; set; } + + // /// + // /// (!) Setting this will trigger a very specific type of game that will affect the AppVersion. + // /// TODO: Is leaving as null the same as commenting out? + // /// + // [JsonProperty("session_config")] + // public SessionConfigData SessionConfig { get; set; } + + [JsonProperty("probe")] + public ProbeData Probe { get; set; } = new ProbeData(); // MIRROR CHANGE: 'new()' not supported in Unity 2020 + + [JsonProperty("envs")] + public EnvsData[] Envs { get; set; } = {}; + + public class SessionConfigData + { + [JsonProperty("kind")] + public string Kind { get; set; } = "Seat"; + + [JsonProperty("sockets")] + public int Sockets { get; set; } = 10; + + [JsonProperty("autodeploy")] + public bool Autodeploy { get; set; } = true; + + [JsonProperty("empty_ttl")] + public int EmptyTtl { get; set; } = 60; + + [JsonProperty("session_max_duration")] + public int SessionMaxDuration { get; set; } = 60; + } + + public class ProbeData + { + [JsonProperty("optimal_ping")] + public int OptimalPing { get; set; } = 60; + + [JsonProperty("rejected_ping")] + public int RejectedPing { get; set; } = 180; + } + + public class EnvsData + { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("is_secret")] + public bool IsSecret { get; set; } = true; + } + #endregion // Optional + + /// Used by Newtonsoft + public UpdateAppVersionRequest() + { + } + + /// + /// Init with required info. Default version/tag == "default". + /// Since we're updating, we only require the AppName. + /// + /// The name of the application. + public UpdateAppVersionRequest(string appName) + { + this.AppName = appName; + } + + /// Parse to json str + public override string ToString() => + JsonConvert.SerializeObject(this); + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs.meta new file mode 100644 index 00000000..eca01ed6 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Requests/UpdateAppVersionRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8da9712633ee1e64faca0b960d4bed31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results.meta new file mode 100644 index 00000000..63ab7622 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa4ceffbc97b8254885a63937def2324 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs new file mode 100644 index 00000000..407d681a --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for `POST v1/deploy`. + /// + public class CreateDeploymentResult + { + [JsonProperty("request_id")] + public string RequestId { get; set; } + + [JsonProperty("request_dns")] + public string RequestDns { get; set; } + + [JsonProperty("request_app")] + public string RequestApp { get; set; } + + [JsonProperty("request_version")] + public string RequestVersion { get; set; } + + [JsonProperty("request_user_count")] + public int RequestUserCount { get; set; } + + [JsonProperty("city")] + public string City { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + + [JsonProperty("continent")] + public string Continent { get; set; } + + [JsonProperty("administrative_division")] + public string AdministrativeDivision { get; set; } + + [JsonProperty("tags")] + public string[] Tags { get; set; } + + [JsonProperty("container_log_storage")] + public ContainerLogStorageData ContainerLogStorage { get; set; } + + + public class ContainerLogStorageData + { + [JsonProperty("enabled")] + public bool Enabled { get; set; } + + [JsonProperty("endpoint_storage")] + public string EndpointStorage { get; set; } + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs.meta new file mode 100644 index 00000000..23484d23 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/CreateDeploymentResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8361abc6f84fccd4cba26dc285d335dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs new file mode 100644 index 00000000..55b03f2c --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// Edgegap error, generally just containing `message` + public class EdgegapErrorResult + { + /// Friendly, UI-facing error message from Edgegap; can be lengthy. + [JsonProperty("message")] + public string ErrorMessage { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs.meta new file mode 100644 index 00000000..be171dd6 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapErrorResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b29093cb10cf3040b76f4fbe77a435d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs new file mode 100644 index 00000000..55b4892b --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs @@ -0,0 +1,118 @@ +using System; +using System.Net; +using System.Net.Http; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using UnityEngine; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Wraps the inner json data with outer http info. + /// This class overload contains no json-deserialiable data result. + /// + public class EdgegapHttpResult + { + /// HTTP Status code for the request. + public HttpStatusCode StatusCode { get; } + + /// This could be err, success, or null. + public string Json { get; } + + /// eg: "POST" + public HttpMethod HttpMethod; + + /// + /// Typically is sent by servers together with the status code. + /// Useful for fallback err descriptions, often based on the status code. + /// + public string ReasonPhrase { get; } + + /// Contains `message` with friendly info. + public bool HasErr => Error != null; + public EdgegapErrorResult Error { get; set; } + + #region Common Shortcuts + /// OK + public bool IsResultCode200 => StatusCode == HttpStatusCode.OK; + + /// NoContent + public bool IsResultCode204 => StatusCode == HttpStatusCode.NoContent; + + /// Forbidden + public bool IsResultCode403 => StatusCode == HttpStatusCode.Forbidden; + + /// Conflict + public bool IsResultCode409 => StatusCode == HttpStatusCode.Conflict; + + /// BadRequest + public bool IsResultCode400 => StatusCode == HttpStatusCode.BadRequest; + + /// Gone + public bool IsResultCode410 => StatusCode == HttpStatusCode.Gone; + #endregion // Common Shortcuts + + + /// + /// Constructor that initializes the class based on an HttpResponseMessage. + /// + public EdgegapHttpResult(HttpResponseMessage httpResponse) + { + this.ReasonPhrase = httpResponse.ReasonPhrase; + this.StatusCode = httpResponse.StatusCode; + + try + { + // TODO: This can be read async with `await`, but can't do this in a Constructor. + // Instead, make a factory builder Task => + this.Json = httpResponse.Content.ReadAsStringAsync().Result; + + this.Error = JsonConvert.DeserializeObject(Json); + if (Error != null && string.IsNullOrEmpty(Error.ErrorMessage)) + Error = null; + } + catch (Exception e) + { + Debug.LogError("Error (reading httpResponse.Content): Client expected json, " + + $"but server returned !json: {e} - "); + } + } + } + + /// + /// Wraps the inner json data with outer http info. + /// This class overload contains json-deserialiable data result. + /// + public class EdgegapHttpResult : EdgegapHttpResult + { + /// The actual result model from Json. Could be null! + public TResult Data { get; set; } + + + public EdgegapHttpResult(HttpResponseMessage httpResponse, bool isLogLevelDebug = false) + : base(httpResponse) + { + this.HttpMethod = httpResponse.RequestMessage.Method; + + // Assuming JSON content and using Newtonsoft.Json for deserialization + bool isDeserializable = httpResponse.Content != null && + httpResponse.Content.Headers.ContentType.MediaType == "application/json"; + + if (isDeserializable) + { + try + { + this.Data = JsonConvert.DeserializeObject(Json); + } + catch (Exception e) + { + Debug.LogError($"Error (deserializing EdgegapHttpResult.Data): {e} - json: {Json}"); + throw; + } + } + + if (isLogLevelDebug) + UnityEngine.Debug.Log($"{typeof(TResult).Name} result: {JObject.Parse(Json)}"); // Prettified + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs.meta new file mode 100644 index 00000000..bc679750 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/EdgegapHttpResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 888bfc2c113487b44a3103648d2c2ae3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs new file mode 100644 index 00000000..b9df98f4 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for `[GET | POST] v1/app`. + /// POST API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/application-post + /// GET API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/application-get + /// + public class GetCreateAppResult + { + [JsonProperty("name")] + public string AppName { get; set; } + + [JsonProperty("is_active")] + public bool IsActive { get; set; } + + /// Optional + [JsonProperty("is_telemetry_agent_active")] + public bool IsTelemetryAgentActive { get; set; } + + [JsonProperty("image")] + public string Image { get; set; } + + [JsonProperty("create_time")] + public string CreateTimeStr { get; set; } + + [JsonProperty("last_updated")] + public string LastUpdatedStr { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs.meta new file mode 100644 index 00000000..ca1a37ee --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetCreateAppResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a66c935238edd8846b1e9e9e19cfab70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs new file mode 100644 index 00000000..57c4540f --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for `GET v1/status/{request_id}`. + /// API Doc | https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-status-get + /// + public class GetDeploymentStatusResult + { + [JsonProperty("request_id")] + public string RequestId { get; set; } + + [JsonProperty("fqdn")] + public string Fqdn { get; set; } + + [JsonProperty("app_name")] + public string AppName { get; set; } + + [JsonProperty("app_version")] + public string AppVersion { get; set; } + + [JsonProperty("current_status")] + public string CurrentStatus { get; set; } + + [JsonProperty("running")] + public bool Running { get; set; } + + [JsonProperty("whitelisting_active")] + public bool WhitelistingActive { get; set; } + + [JsonProperty("start_time")] + public string StartTime { get; set; } + + [JsonProperty("removal_time")] + public string RemovalTime { get; set; } + + [JsonProperty("elapsed_time")] + public int? ElapsedTime { get; set; } + + [JsonProperty("last_status")] + public string LastStatus { get; set; } + + [JsonProperty("error")] + public bool Error { get; set; } + + [JsonProperty("error_detail")] + public string ErrorDetail { get; set; } + + [JsonProperty("public_ip")] + public string PublicIp { get; set; } + + [JsonProperty("sessions")] + public SessionData[] Sessions { get; set; } + + [JsonProperty("location")] + public LocationData Location { get; set; } + + [JsonProperty("tags")] + public string[] Tags { get; set; } + + [JsonProperty("sockets")] + public string Sockets { get; set; } + + [JsonProperty("sockets_usage")] + public string SocketsUsage { get; set; } + + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("arguments")] + public string Arguments { get; set; } + + /// + /// TODO: Server should swap `ports` to an array of DeploymentPortsData (instead of an object of dynamic unknown objects). + /// + /// { + /// "7777", {} + /// }, + /// { + /// "Some Port Name", {} + /// } + /// + /// + [JsonProperty("ports")] + public Dictionary PortsDict { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs.meta new file mode 100644 index 00000000..55eef85f --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetDeploymentStatusResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c658b7f5c5d5d0648934b0ae1d71de9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs new file mode 100644 index 00000000..8c3bd545 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for `GET v1/wizard/registry-credentials`. + /// + public class GetRegistryCredentialsResult + { + [JsonProperty("registry_url")] + public string RegistryUrl { get; set; } + + [JsonProperty("project")] + public string Project { get; set; } + + [JsonProperty("username")] + public string Username { get; set; } + + [JsonProperty("token")] + public string Token { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs.meta new file mode 100644 index 00000000..d8b5099d --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetRegistryCredentialsResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e6af130c329d2b43b2f4b0dc8639477 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs new file mode 100644 index 00000000..71d76b77 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for `GET v1/ip`. + /// GET API Doc | https://docs.edgegap.com/api/#tag/IP-Lookup/operation/IP + /// + public class GetYourPublicIpResult + { + [JsonProperty("public_ip")] + public string PublicIp { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs.meta new file mode 100644 index 00000000..4f6f0ae3 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/GetYourPublicIpResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73c9651ef0fdfcb449ec0120016963a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs new file mode 100644 index 00000000..5d4d6a0b --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs @@ -0,0 +1,89 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + public class StopActiveDeploymentResult + { + [JsonProperty("message")] + public string Message { get; set; } + + [JsonProperty("deployment_summary")] + public DeploymentSummaryData DeploymentSummary { get; set; } + + + public class DeploymentSummaryData + { + [JsonProperty("request_id")] + public string RequestId { get; set; } + + [JsonProperty("fqdn")] + public string Fqdn { get; set; } + + [JsonProperty("app_name")] + public string AppName { get; set; } + + [JsonProperty("app_version")] + public string AppVersion { get; set; } + + [JsonProperty("current_status")] + public string CurrentStatus { get; set; } + + [JsonProperty("running")] + public bool Running { get; set; } + + [JsonProperty("whitelisting_active")] + public bool WhitelistingActive { get; set; } + + [JsonProperty("start_time")] + public string StartTime { get; set; } + + [JsonProperty("removal_time")] + public string RemovalTime { get; set; } + + [JsonProperty("elapsed_time")] + public int ElapsedTime { get; set; } + + [JsonProperty("last_status")] + public string LastStatus { get; set; } + + [JsonProperty("error")] + public bool Error { get; set; } + + [JsonProperty("error_detail")] + public string ErrorDetail { get; set; } + + [JsonProperty("ports")] + public PortsData Ports { get; set; } + + [JsonProperty("public_ip")] + public string PublicIp { get; set; } + + [JsonProperty("sessions")] + public SessionData[] Sessions { get; set; } + + [JsonProperty("location")] + public LocationData Location { get; set; } + + [JsonProperty("tags")] + public string[] Tags { get; set; } + + [JsonProperty("sockets")] + public string Sockets { get; set; } + + [JsonProperty("sockets_usage")] + public string SocketsUsage { get; set; } + + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("arguments")] + public string Arguments { get; set; } + + } + + public class PortsData + { + + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs.meta new file mode 100644 index 00000000..4adcc65a --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/StopActiveDeploymentResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e2e4d9424ca8f7459803e631acf912f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs new file mode 100644 index 00000000..bc869d5f --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs @@ -0,0 +1,165 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models.Results +{ + /// + /// Result model for: + /// - `POST 1/app/{app_name}/version` + /// - `PATCH v1/app/{app_name}/version/{version_name}` + /// POST API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/application-post + /// PATCH API Doc | https://docs.edgegap.com/api/#tag/Applications/operation/app-versions-patch + /// + public class UpsertAppVersionResult + { + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("version")] + public VersionData Version { get; set; } + + public class VersionData + { + [JsonProperty("name")] + public string VersionName { get; set; } + + [JsonProperty("is_active")] + public bool IsActive { get; set; } + + [JsonProperty("docker_repository")] + public string DockerRepository { get; set; } + + [JsonProperty("docker_image")] + public string DockerImage { get; set; } + + [JsonProperty("docker_tag")] + public string DockerTag { get; set; } + + [JsonProperty("private_username")] + public string PrivateUsername { get; set; } + + [JsonProperty("private_token")] + public string PrivateToken { get; set; } + + [JsonProperty("req_cpu")] + public int? ReqCpu { get; set; } + + [JsonProperty("req_memory")] + public int? ReqMemory { get; set; } + + [JsonProperty("req_video")] + public int? ReqVideo { get; set; } + + [JsonProperty("max_duration")] + public int? MaxDuration { get; set; } + + [JsonProperty("use_telemetry")] + public bool UseTelemetry { get; set; } + + [JsonProperty("inject_context_env")] + public bool InjectContextEnv { get; set; } + + [JsonProperty("whitelisting_active")] + public bool WhitelistingActive { get; set; } + + [JsonProperty("force_cache")] + public bool ForceCache { get; set; } + + [JsonProperty("cache_min_hour")] + public int? CacheMinHour { get; set; } + + [JsonProperty("cache_max_hour")] + public int? CacheMaxHour { get; set; } + + [JsonProperty("time_to_deploy")] + public int? TimeToDeploy { get; set; } + + [JsonProperty("enable_all_locations")] + public bool EnableAllLocations { get; set; } + + [JsonProperty("session_config")] + public SessionConfigData SessionConfig { get; set; } + + [JsonProperty("ports")] + public PortsData[] Ports { get; set; } + + [JsonProperty("probe")] + public ProbeData Probe { get; set; } + + [JsonProperty("envs")] + public EnvsData[] Envs { get; set; } + + [JsonProperty("verify_image")] + public bool VerifyImage { get; set; } + + [JsonProperty("termination_grace_period_seconds")] + public int? TerminationGracePeriodSeconds { get; set; } + + [JsonProperty("endpoint_storage")] + public string EndpointStorage { get; set; } + + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("arguments")] + public string Arguments { get; set; } + } + + public class SessionConfigData + { + [JsonProperty("kind")] + public string Kind { get; set; } + + [JsonProperty("sockets")] + public int? Sockets { get; set; } + + [JsonProperty("autodeploy")] + public bool Autodeploy { get; set; } + + [JsonProperty("empty_ttl")] + public int? EmptyTtl { get; set; } + + [JsonProperty("session_max_duration")] + public int? SessionMaxDuration { get; set; } + } + + public class PortsData + { + [JsonProperty("port")] + public int? Port { get; set; } + + [JsonProperty("protocol")] + public string Protocol { get; set; } + + [JsonProperty("to_check")] + public bool ToCheck { get; set; } + + [JsonProperty("tls_upgrade")] + public bool TlsUpgrade { get; set; } + + [JsonProperty("name")] + public string PortName { get; set; } + } + + public class ProbeData + { + [JsonProperty("optimal_ping")] + public int? OptimalPing { get; set; } + + [JsonProperty("rejected_ping")] + public int? RejectedPing { get; set; } + } + + public class EnvsData + { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } + + [JsonProperty("is_secret")] + public bool IsSecret { get; set; } + } + + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs.meta new file mode 100644 index 00000000..e08dbf44 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/Results/UpsertAppVersionResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7dde7d59c66d8c44b86af35e853f9f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs new file mode 100644 index 00000000..458da78d --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Edgegap.Editor.Api.Models +{ + /// + /// Shared model for `GetDeploymentStatusResult`, `StopActiveDeploymentResult`. + /// + public class SessionData + { + [JsonProperty("session_id")] + public string SessionId { get; set; } + + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("ready")] + public bool Ready { get; set; } + + [JsonProperty("linked")] + public bool Linked { get; set; } + + [JsonProperty("kind")] + public string Kind { get; set; } + + [JsonProperty("user_count")] + public string UserCount { get; set; } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs.meta new file mode 100644 index 00000000..86d9d288 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/Api/Models/SessionData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f9024e4ca5438e4788e461387313531 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs b/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs new file mode 100644 index 00000000..40203eaa --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using UnityEngine.UIElements; + +namespace Edgegap.Editor +{ + /// Slightly shake a UI button to indicate attention. + public class ButtonShaker + { + const string SHAKE_START_CLASS = "shakeStart"; + const string SHAKE_STOP_CLASS = "shakeEnd"; + private Button targetButton; + + public ButtonShaker(Button buttonToShake) => + targetButton = buttonToShake; + + /// Shake the button x times for x msDelayBetweenShakes each. + /// 1 shake = 1 bigger -> followed by 1 smaller. + /// + /// # of shakes + public async Task ApplyShakeAsync(int msDelayBetweenShakes = 40, int iterations = 2) + { + for (int i = 0; i < iterations; i++) + await shakeOnce(msDelayBetweenShakes); + } + + private async Task shakeOnce(int msDelayBetweenShakes) + { + targetButton.AddToClassList(SHAKE_START_CLASS); + await Task.Delay(msDelayBetweenShakes); // duration of the first transition + targetButton.RemoveFromClassList(SHAKE_START_CLASS); + + targetButton.AddToClassList(SHAKE_STOP_CLASS); + await Task.Delay(msDelayBetweenShakes); // duration of the second transition + targetButton.RemoveFromClassList(SHAKE_STOP_CLASS); + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs.meta new file mode 100644 index 00000000..7272ca69 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/ButtonShaker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f963d64ffcf32ba4bba54fe1cd70b5a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs new file mode 100644 index 00000000..50d814ab --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build.Reporting; + +using Debug = UnityEngine.Debug; + +namespace Edgegap +{ + internal static class EdgegapBuildUtils + { + public static bool IsArmCPU() => + RuntimeInformation.ProcessArchitecture == Architecture.Arm || + RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + + public static BuildReport BuildServer() + { + IEnumerable scenes = EditorBuildSettings.scenes.Select(s=>s.path); + BuildPlayerOptions options = new BuildPlayerOptions + { + scenes = scenes.ToArray(), + target = BuildTarget.StandaloneLinux64, + // MIRROR CHANGE +#if UNITY_2021_3_OR_NEWER + subtarget = (int)StandaloneBuildSubtarget.Server, // dedicated server with UNITY_SERVER define +#else + options = BuildOptions.EnableHeadlessMode, // obsolete and missing UNITY_SERVER define +#endif + // END MIRROR CHANGE + locationPathName = "Builds/EdgegapServer/ServerBuild" + }; + + return BuildPipeline.BuildPlayer(options); + } + + public static async Task DockerSetupAndInstallationCheck() + { + if (!File.Exists("Dockerfile")) + { + File.WriteAllText("Dockerfile", dockerFileText); + } + + string output = null; + string error = null; + await RunCommand_DockerVersion(msg => output = msg, msg => error = msg); // MIRROR CHANGE + if (!string.IsNullOrEmpty(error)) + { + Debug.LogError(error); + return false; + } + Debug.Log($"[Edgegap] Docker version detected: {output}"); // MIRROR CHANGE + return true; + } + + // MIRROR CHANGE + static async Task RunCommand_DockerVersion(Action outputReciever = null, Action errorReciever = null) + { +#if UNITY_EDITOR_WIN + await RunCommand("cmd.exe", "/c docker --version", outputReciever, errorReciever); +#elif UNITY_EDITOR_OSX + await RunCommand("/bin/bash", "-c \"docker --version\"", outputReciever, errorReciever); +#elif UNITY_EDITOR_LINUX + await RunCommand("/bin/bash", "-c \"docker --version\"", outputReciever, errorReciever); +#else + Debug.LogError("The platform is not supported yet."); +#endif + } + + // MIRROR CHANGE + public static async Task RunCommand_DockerBuild(string registry, string imageRepo, string tag, Action onStatusUpdate) + { + string realErrorMessage = null; + + // ARM -> x86 support: + // build commands use 'buildx' on ARM cpus for cross compilation. + // otherwise docker builds would not launch when deployed because + // Edgegap's infrastructure is on x86. instead the deployment logs + // would show an error in a linux .go file with 'not found'. + string buildCommand = IsArmCPU() ? "buildx build --platform linux/amd64" : "build"; + +#if UNITY_EDITOR_WIN + await RunCommand("docker.exe", $"{buildCommand} -t {registry}/{imageRepo}:{tag} .", onStatusUpdate, +#elif UNITY_EDITOR_OSX + await RunCommand("/bin/bash", $"-c \"docker {buildCommand} -t {registry}/{imageRepo}:{tag} .\"", onStatusUpdate, +#elif UNITY_EDITOR_LINUX + await RunCommand("/bin/bash", $"-c \"docker {buildCommand} -t {registry}/{imageRepo}:{tag} .\"", onStatusUpdate, +#endif + (msg) => + { + if (msg.Contains("ERROR")) + { + realErrorMessage = msg; + } + onStatusUpdate(msg); + }); + + if(realErrorMessage != null) + { + throw new Exception(realErrorMessage); + } + } + + public static async Task<(bool, string)> RunCommand_DockerPush(string registry, string imageRepo, string tag, Action onStatusUpdate) + { + string error = string.Empty; +#if UNITY_EDITOR_WIN + await RunCommand("docker.exe", $"push {registry}/{imageRepo}:{tag}", onStatusUpdate, (msg) => error += msg + "\n"); +#elif UNITY_EDITOR_OSX + await RunCommand("/bin/bash", $"-c \"docker push {registry}/{imageRepo}:{tag}\"", onStatusUpdate, (msg) => error += msg + "\n"); +#elif UNITY_EDITOR_LINUX + await RunCommand("/bin/bash", $"-c \"docker push {registry}/{imageRepo}:{tag}\"", onStatusUpdate, (msg) => error += msg + "\n"); +#endif + if (!string.IsNullOrEmpty(error)) + { + Debug.LogError(error); + return (false, error); + } + return (true, null); + } + // END MIRROR CHANGE + + static async Task RunCommand(string command, string arguments, Action outputReciever = null, Action errorReciever = null) + { + ProcessStartInfo startInfo = new ProcessStartInfo() + { + FileName = command, + Arguments = arguments, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }; + + // MIRROR CHANGE +#if !UNITY_EDITOR_WIN + // on mac, commands like 'docker' aren't found because it's not in the application's PATH + // even if it runs on mac's terminal. + // to solve this we need to do two steps: + // 1. add /usr/bin/local to PATH if it's not there already. often this is missing in the application. + // this is where docker is usually instaled. + // 2. add PATH to ProcessStartInfo + string existingPath = Environment.GetEnvironmentVariable("PATH"); + string customPath = $"{existingPath}:/usr/local/bin"; + startInfo.EnvironmentVariables["PATH"] = customPath; + // Debug.Log("PATH: " + customPath); +#endif + // END MIRROR CHANGE + + Process proc = new Process() { StartInfo = startInfo, }; + proc.EnableRaisingEvents = true; + + ConcurrentQueue errors = new ConcurrentQueue(); + ConcurrentQueue outputs = new ConcurrentQueue(); + + void pipeQueue(ConcurrentQueue q, Action opt) + { + while (!q.IsEmpty) + { + if (q.TryDequeue(out string msg) && !string.IsNullOrWhiteSpace(msg)) + { + opt?.Invoke(msg); + } + } + } + + proc.OutputDataReceived += (s, e) => outputs.Enqueue(e.Data); + proc.ErrorDataReceived += (s, e) => errors.Enqueue(e.Data); + + proc.Start(); + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + + while (!proc.HasExited) + { + await Task.Delay(100); + pipeQueue(errors, errorReciever); + pipeQueue(outputs, outputReciever); + } + + pipeQueue(errors, errorReciever); + pipeQueue(outputs, outputReciever); + + + } + + static void Proc_OutputDataReceived(object sender, DataReceivedEventArgs e) + { + throw new NotImplementedException(); + } + + static Regex lastDigitsRegex = new Regex("([0-9])+$"); + + public static string IncrementTag(string tag) + { + Match lastDigits = lastDigitsRegex.Match(tag); + if (!lastDigits.Success) + { + return tag + " _1"; + } + + int number = int.Parse(lastDigits.Groups[0].Value); + + number++; + + return lastDigitsRegex.Replace(tag, number.ToString()); + } + + public static void UpdateEdgegapAppTag(string tag) + { + // throw new NotImplementedException(); + } + + // -batchmode -nographics remains for Unity 2019/2020 support pre-dedicated server builds + static string dockerFileText = @"FROM ubuntu:bionic + +ARG DEBIAN_FRONTEND=noninteractive + +COPY Builds/EdgegapServer /root/build/ + +WORKDIR /root/ + +RUN chmod +x /root/build/ServerBuild + +ENTRYPOINT [ ""/root/build/ServerBuild"", ""-batchmode"", ""-nographics""] +"; + + /// Run a Docker cmd with streaming log response. TODO: Plugin to other Docker cmds + /// Throws if logs contain "ERROR" + /// + /// ex: "registry.edgegap.com" + /// ex: "robot$mycompany-asdf+client-push" + /// Different from ApiToken; sometimes called "Container Registry Password" + /// Log stream + // MIRROR CHANGE: CROSS PLATFORM SUPPORT + static async Task RunCommand_DockerLogin( + string registryUrl, + string repoUsername, + string repoPasswordToken, + Action outputReciever = null, Action errorReciever = null) + { + // TODO: Use --password-stdin for security (!) This is no easy task for child Process | https://stackoverflow.com/q/51489359/6541639 + // (!) Don't use single quotes for cross-platform support (works unexpectedly in `cmd`). + + try + { +#if UNITY_EDITOR_WIN + await RunCommand("cmd.exe", $"/c docker login -u \"{repoUsername}\" --password \"{repoPasswordToken}\" \"{registryUrl}\"", outputReciever, errorReciever); +#elif UNITY_EDITOR_OSX + await RunCommand("/bin/bash", $"-c \"docker login -u \"{repoUsername}\" --password \"{repoPasswordToken}\" \"{registryUrl}\"\"", outputReciever, errorReciever); +#elif UNITY_EDITOR_LINUX + await RunCommand("/bin/bash", $"-c \"docker login -u \"{repoUsername}\" --password \"{repoPasswordToken}\" \"{registryUrl}\"\"", outputReciever, errorReciever); +#else + Debug.LogError("The platform is not supported yet."); +#endif + } + catch (Exception e) + { + Debug.LogError($"Error: {e}"); + return false; + } + + return true; + } + + /// + /// v2: Login to Docker Registry via RunCommand(), returning streamed log messages: + /// "docker login {registryUrl} {repository} {repoUsername} {repoPasswordToken}" + /// + /// ex: "registry.edgegap.com" + /// ex: "robot$mycompany-asdf+client-push" + /// Different from ApiToken; sometimes called "Container Registry Password" + /// Log stream + /// isSuccess + public static async Task LoginContainerRegistry( + string registryUrl, + string repoUsername, + string repoPasswordToken, + Action onStatusUpdate) + { + string error = null; + await RunCommand_DockerLogin(registryUrl, repoUsername, repoPasswordToken, onStatusUpdate, msg => error = msg); // MIRROR CHANGE + if (error.Contains("ERROR")) + { + Debug.LogError(error); + return false; + } + return true; + } + + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs.meta new file mode 100644 index 00000000..03529c42 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97dadab2a073d8b47bf9a270401f0a8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs new file mode 100644 index 00000000..a01f1c71 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs @@ -0,0 +1,25 @@ +using UnityEditor; +using UnityEngine.UIElements; +using Edgegap; + +[CustomEditor(typeof(EdgegapToolScript))] +public class EdgegapPluginScriptEditor : Editor +{ + VisualElement _serverDataContainer; + + private void OnEnable() + { + _serverDataContainer = EdgegapServerDataManager.GetServerDataVisualTree(); + EdgegapServerDataManager.RegisterServerDataContainer(_serverDataContainer); + } + + private void OnDisable() + { + EdgegapServerDataManager.DeregisterServerDataContainer(_serverDataContainer); + } + + public override VisualElement CreateInspectorGUI() + { + return _serverDataContainer; + } +} \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs.meta new file mode 100644 index 00000000..60f708f6 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapScriptEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4c676ae6dcca0e458c6a8f06571f8fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss new file mode 100644 index 00000000..15cb5e39 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss @@ -0,0 +1,81 @@ +.row__port-table { + padding: 2px 4px; + display: flex; + flex-direction: row; + align-items: center; + width: auto; + justify-content: space-around; + -unity-text-align: middle-left; +} + + .row__port-table > * { + width: 0px; + flex-grow: 1; + align-self: center; + margin: 0px; + padding: 0px; + } + +.focusable:hover { + background-color: rgba(0,0,0,0.2); + border-radius: 3px; +} + +.row__dns { + display: flex; + flex-direction: row; + align-items: center; + width: auto; + justify-content: space-between; + -unity-text-align: middle-left; +} + +.row__status { + display: flex; + flex-direction: row; + align-items: center; + width: auto; + justify-content: space-between; + -unity-text-align: middle-left; +} + +.label__header { + -unity-font-style: bold +} + +.label__status { + -unity-font-style: bold; + border-radius: 2px; + width: 100px; + color: #fff; + -unity-text-align: middle-center; +} + +.label__info-text { + padding: 8px; + margin: 4px; + border-radius: 3px; + -unity-text-align: middle-center; + white-space: normal; + background-color: rgba(42, 42, 42, 0.5); +} + +.container { + margin: 8px 0px; +} + +.bg--secondary { + background-color: #8a8a8a; +} + +.bg--success { + background-color: #90be6d; +} + +.bg--danger { + background-color: #f94144; +} + +.bg--warning { + background-color: #f9c74f; +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss.meta b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss.meta new file mode 100644 index 00000000..b9cce488 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerData.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da5e3f58bd8cde14789f7c61df3f59f4 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs new file mode 100644 index 00000000..7ed5c0e8 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs @@ -0,0 +1,240 @@ +using IO.Swagger.Model; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Edgegap +{ + static class EdgegapServerDataManagerUtils + { + public static Label GetHeader(string text) + { + Label header = new Label(text); + header.AddToClassList("label__header"); + + return header; + } + + public static VisualElement GetHeaderRow() + { + VisualElement row = new VisualElement(); + row.AddToClassList("row__port-table"); + row.AddToClassList("label__header"); + + row.Add(new Label("Name")); + row.Add(new Label("External")); + row.Add(new Label("Internal")); + row.Add(new Label("ProtocolStr")); + row.Add(new Label("Link")); + + return row; + } + + public static VisualElement GetRowFromPortResponse(PortMapping port) + { + VisualElement row = new VisualElement(); + row.AddToClassList("row__port-table"); + row.AddToClassList("focusable"); + + + row.Add(new Label(port.Name)); + row.Add(new Label(port.External.ToString())); + row.Add(new Label(port.Internal.ToString())); + row.Add(new Label(port.Protocol)); + row.Add(GetCopyButton("Copy", port.Link)); + + return row; + } + + public static Button GetCopyButton(string btnText, string copiedText) + { + Button copyBtn = new Button(); + copyBtn.text = btnText; + copyBtn.clickable.clicked += () => GUIUtility.systemCopyBuffer = copiedText; + + return copyBtn; + } + + public static Button GetLinkButton(string btnText, string targetUrl) + { + Button copyBtn = new Button(); + copyBtn.text = btnText; + copyBtn.clickable.clicked += () => UnityEngine.Application.OpenURL(targetUrl); + + return copyBtn; + } + public static Label GetInfoText(string innerText) + { + Label infoText = new Label(innerText); + infoText.AddToClassList("label__info-text"); + + return infoText; + } + } + + /// + /// Utility class to centrally manage the Edgegap server data, and create / update the elements displaying the server info. + /// + public static class EdgegapServerDataManager + { + internal static Status _serverData; + private static ApiEnvironment _apiEnvironment; + + // UI elements + private static readonly StyleSheet _serverDataStylesheet; + private static readonly List _serverDataContainers = new List(); + + public static Status GetServerStatus() => _serverData; + + static EdgegapServerDataManager() + { + _serverDataStylesheet = AssetDatabase.LoadAssetAtPath("Assets/Edgegap/Editor/EdgegapServerData.uss"); + } + public static void RegisterServerDataContainer(VisualElement serverDataContainer) + { + _serverDataContainers.Add(serverDataContainer); + } + public static void DeregisterServerDataContainer(VisualElement serverDataContainer) + { + _serverDataContainers.Remove(serverDataContainer); + } + public static void SetServerData(Status serverData, ApiEnvironment apiEnvironment) + { + _serverData = serverData; + _apiEnvironment = apiEnvironment; + RefreshServerDataContainers(); + } + + private static VisualElement GetStatusSection() + { + ServerStatus serverStatus = _serverData.GetServerStatus(); + string dashboardUrl = _apiEnvironment.GetDashboardUrl(); + string requestId = _serverData.RequestId; + string deploymentDashboardUrl = ""; + + if (!string.IsNullOrEmpty(requestId) && !string.IsNullOrEmpty(dashboardUrl)) + { + deploymentDashboardUrl = $"{dashboardUrl}/arbitrium/deployment/read/{requestId}/"; + } + + VisualElement container = new VisualElement(); + container.AddToClassList("container"); + + container.Add(EdgegapServerDataManagerUtils.GetHeader("Server Status")); + + VisualElement row = new VisualElement(); + row.AddToClassList("row__status"); + + // Status pill + Label statusLabel = new Label(serverStatus.GetLabelText()); + statusLabel.AddToClassList(serverStatus.GetStatusBgClass()); + statusLabel.AddToClassList("label__status"); + row.Add(statusLabel); + + // Link to dashboard + if (!string.IsNullOrEmpty(deploymentDashboardUrl)) + { + row.Add(EdgegapServerDataManagerUtils.GetLinkButton("See in the dashboard", deploymentDashboardUrl)); + } + else + { + row.Add(new Label("Could not resolve link to this deployment")); + } + + container.Add(row); + + return container; + } + + private static VisualElement GetDnsSection() + { + string serverDns = _serverData.Fqdn; + + VisualElement container = new VisualElement(); + container.AddToClassList("container"); + + container.Add(EdgegapServerDataManagerUtils.GetHeader("Server DNS")); + + VisualElement row = new VisualElement(); + row.AddToClassList("row__dns"); + row.AddToClassList("focusable"); + + row.Add(new Label(serverDns)); + row.Add(EdgegapServerDataManagerUtils.GetCopyButton("Copy", serverDns)); + + container.Add(row); + + return container; + } + + private static VisualElement GetPortsSection() + { + List serverPorts = _serverData.Ports.Values.ToList(); + + VisualElement container = new VisualElement(); + container.AddToClassList("container"); + + container.Add(EdgegapServerDataManagerUtils.GetHeader("Server PortsDict")); + container.Add(EdgegapServerDataManagerUtils.GetHeaderRow()); + + VisualElement portList = new VisualElement(); + + if (serverPorts.Count > 0) + { + foreach (PortMapping port in serverPorts) + { + portList.Add(EdgegapServerDataManagerUtils.GetRowFromPortResponse(port)); + } + } + else + { + portList.Add(new Label("No port configured for this app version.")); + } + + container.Add(portList); + + return container; + } + + public static VisualElement GetServerDataVisualTree() + { + VisualElement serverDataTree = new VisualElement(); + serverDataTree.styleSheets.Add(_serverDataStylesheet); + + bool hasServerData = _serverData != null; + bool isReady = hasServerData && _serverData.GetServerStatus().IsOneOf(ServerStatus.Ready, ServerStatus.Error); + + if (hasServerData) + { + serverDataTree.Add(GetStatusSection()); + + if (isReady) + { + serverDataTree.Add(GetDnsSection()); + serverDataTree.Add(GetPortsSection()); + } + else + { + serverDataTree.Add(EdgegapServerDataManagerUtils.GetInfoText("Additional information will be displayed when the server is ready.")); + } + } + else + { + serverDataTree.Add(EdgegapServerDataManagerUtils.GetInfoText("Server data will be displayed here when a server is running.")); + } + + return serverDataTree; + } + + private static void RefreshServerDataContainers() + { + foreach (VisualElement serverDataContainer in _serverDataContainers) + { + serverDataContainer.Clear(); + serverDataContainer.Add(GetServerDataVisualTree()); // Cannot reuse a same instance of VisualElement + } + } + } +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs.meta new file mode 100644 index 00000000..65da2ab4 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapServerDataManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 39f5f27c13279a34eb116630a00e41c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs new file mode 100644 index 00000000..870190d2 --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs @@ -0,0 +1,12 @@ +using UnityEngine; +using Edgegap; +using IO.Swagger.Model; + +/// +/// This script acts as an interface to display and use the necessary variables from the Edgegap tool. +/// The server info can be accessed from the tool window, as well as through the public script property. +/// +public class EdgegapToolScript : MonoBehaviour +{ + public Status ServerStatus => EdgegapServerDataManager.GetServerStatus(); +} diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs.meta b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs.meta new file mode 100644 index 00000000..d584893d --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapToolScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5963202433da25448a22def99f5a598b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.cs new file mode 100644 index 00000000..bf42be0e --- /dev/null +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindow.cs @@ -0,0 +1,983 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Collections.Generic; +using Newtonsoft.Json; +using System.Net; +using System.Text; +using System; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using IO.Swagger.Model; +using UnityEditor.Build.Reporting; +using Application = UnityEngine.Application; + +namespace Edgegap +{ + public class EdgegapWindow : EditorWindow + { + // MIRROR CHANGE: create HTTPClient in-place to avoid InvalidOperationExceptions when reusing + // static readonly HttpClient _httpClient = new HttpClient(); + // END MIRROR CHANGE + + const string EditorDataSerializationName = "EdgegapSerializationData"; + const int ServerStatusCronjobIntervalMs = 10000; // Interval at which the server status is updated + + // MIRROR CHANGE + // get the path of this .cs file so we don't need to hardcode paths to + // the .uxml and .uss files: + // https://forum.unity.com/threads/too-many-hard-coded-paths-in-the-templates-and-documentation.728138/ + // this way users can move this folder without breaking UIToolkit paths. + internal string StylesheetPath => + Path.GetDirectoryName(AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(this))); + // END MIRROR CHANGE + + readonly System.Timers.Timer _updateServerStatusCronjob = new System.Timers.Timer(ServerStatusCronjobIntervalMs); + + [SerializeField] string _userExternalIp; + [SerializeField] string _apiKey; + [SerializeField] ApiEnvironment _apiEnvironment; + [SerializeField] string _appName; + [SerializeField] string _appVersionName; + [SerializeField] string _deploymentRequestId; + + [SerializeField] string _containerRegistry; + [SerializeField] string _containerImageRepo; + [SerializeField] string _containerImageTag; + [SerializeField] bool _autoIncrementTag = true; + + + VisualTreeAsset _visualTree; + bool _shouldUpdateServerStatus = false; + + // Interactable elements + EnumField _apiEnvironmentSelect; + TextField _apiKeyInput; + TextField _appNameInput; + TextField _appVersionNameInput; + TextField _containerRegistryInput; + TextField _containerImageRepoInput; + TextField _containerImageTagInput; + Toggle _autoIncrementTagInput; + Button _connectionButton; + Button _serverActionButton; + Button _documentationBtn; + Button _buildAndPushServerBtn; + + // Readonly elements + Label _connectionStatusLabel; + VisualElement _serverDataContainer; + + // server data manager + StyleSheet _serverDataStylesheet; + List _serverDataContainers = new List(); + + [Obsolete("See EdgegapWindowV2.ShowEdgegapToolWindow()")] + // [MenuItem("Edgegap/Server Management")] + public static void ShowEdgegapToolWindow() + { + EdgegapWindow window = GetWindow(); + window.titleContent = new GUIContent("Edgegap Hosting"); // MIRROR CHANGE + } + + protected void OnEnable() + { + // Set root VisualElement and style + // BEGIN MIRROR CHANGE + _visualTree = AssetDatabase.LoadAssetAtPath($"{StylesheetPath}/EdgegapWindow.uxml"); + StyleSheet styleSheet = AssetDatabase.LoadAssetAtPath($"{StylesheetPath}/EdgegapWindow.uss"); + _serverDataStylesheet = AssetDatabase.LoadAssetAtPath($"{StylesheetPath}/EdgegapServerData.uss"); + // END MIRROR CHANGE + rootVisualElement.styleSheets.Add(styleSheet); + + LoadToolData(); + + if (string.IsNullOrWhiteSpace(_userExternalIp)) + { + _userExternalIp = GetExternalIpAddress(); + } + } + + protected void Update() + { + if (_shouldUpdateServerStatus) + { + _shouldUpdateServerStatus = false; + UpdateServerStatus(); + } + } + + public void CreateGUI() + { + rootVisualElement.Clear(); + _visualTree.CloneTree(rootVisualElement); + + InitUIElements(); + SyncFormWithObject(); + + bool hasActiveDeployment = !string.IsNullOrEmpty(_deploymentRequestId); + + if (hasActiveDeployment) + { + RestoreActiveDeployment(); + } + else + { + DisconnectCallback(); + } + } + + protected void OnDestroy() + { + bool deploymentActive = !string.IsNullOrEmpty(_deploymentRequestId); + + if (deploymentActive) + { + EditorUtility.DisplayDialog( + "Warning", + $"You have an active deployment ({_deploymentRequestId}) that won't be stopped automatically.", + "Ok" + ); + } + } + + protected void OnDisable() + { + SyncObjectWithForm(); + SaveToolData(); + DeregisterServerDataContainer(_serverDataContainer); + } + + /// + /// Binds the form inputs to the associated variables and initializes the inputs as required. + /// Requires the VisualElements to be loaded before this call. Otherwise, the elements cannot be found. + /// + void InitUIElements() + { + _apiEnvironmentSelect = rootVisualElement.Q("environmentSelect"); + _apiKeyInput = rootVisualElement.Q("apiKey"); + _appNameInput = rootVisualElement.Q("appName"); + _appVersionNameInput = rootVisualElement.Q("appVersionName"); + + _containerRegistryInput = rootVisualElement.Q("containerRegistry"); + _containerImageRepoInput = rootVisualElement.Q("containerImageRepo"); + _containerImageTagInput = rootVisualElement.Q("tag"); + _autoIncrementTagInput = rootVisualElement.Q("autoIncrementTag"); + + _connectionButton = rootVisualElement.Q