diff --git a/.gitignore b/.gitignore index 966815b4..35c80e62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,432 @@ .vs -obj -bin +[Oo]bj/ +[Bb]in/ AutoEvent.csproj.user packages Music.tar Music.tar.gz Schematics.tar -Schematics.tar.gz \ No newline at end of file +Schematics.tar.gz +VersionInfo.cs +AutoEvent/VersionInfo.cs + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +# Common IntelliJ Platform excludes + +# User specific +**/.idea/**/workspace.xml +**/.idea/**/tasks.xml +**/.idea/shelf/* +**/.idea/dictionaries +**/.idea/httpRequests/ + +# Sensitive or high-churn files +**/.idea/**/dataSources/ +**/.idea/**/dataSources.ids +**/.idea/**/dataSources.xml +**/.idea/**/dataSources.local.xml +**/.idea/**/sqlDataSources.xml +**/.idea/**/dynamic.xml + +# Rider +# Rider auto-generates .iml files, and contentModel.xml +**/.idea/**/*.iml +**/.idea/**/contentModel.xml +**/.idea/**/modules.xml + +[Pp]ackages/ + +Thumbs.db +Desktop.ini +.DS_Store \ No newline at end of file diff --git a/AutoEvent/API/Components/DestructiblePrimitiveComponent.cs b/AutoEvent/API/Components/DestructiblePrimitiveComponent.cs new file mode 100644 index 00000000..d6a74c4c --- /dev/null +++ b/AutoEvent/API/Components/DestructiblePrimitiveComponent.cs @@ -0,0 +1,65 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: DestructiblePrimitiveComponent.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:46 PM +// Created Date: 10/17/2023 6:46 PM +// ----------------------------------------- + +using System; +using AdminToys; +using Mirror; +using PlayerStatsSystem; +using UnityEngine; + +namespace AutoEvent.API.Components; + +public class DestructiblePrimitiveComponent : UnityEngine.MonoBehaviour, IDestructible +{ + public bool Damage(float damage, DamageHandlerBase handler, Vector3 exactHitPos) + { + var ev = new DamagingPrimitiveArgs(damage, handler, exactHitPos); + DamagingPrimitive?.Invoke(ev); + if (!ev.IsAllowed) + { + return false; + } + + Health -= ev.Damage; + if (Health <= 0) + { + + var prim = gameObject.GetComponent(); + NetworkServer.UnSpawn(base.gameObject); + Destroy(gameObject); + } + + return true; + } + + public uint NetworkId { get; } + public Vector3 CenterOfMass { get; } + public float Health { get; private set; } + public event Action DamagingPrimitive; + +} + +public class DamagingPrimitiveArgs +{ + public DamagingPrimitiveArgs(float damage, DamageHandlerBase handler, Vector3 exactHitPos, bool isAllowed = true) + { + Damage = damage; + Handler = handler; + ExactHitPosition = exactHitPos; + IsAllowed = isAllowed; + } + public float Damage { get; set; } + public DamageHandlerBase Handler { get; init; } + public Vector3 ExactHitPosition { get; set; } + public bool IsAllowed { get; set; } + +} \ No newline at end of file diff --git a/AutoEvent/API/Enums/Effects.cs b/AutoEvent/API/Enums/Effects.cs index 739f8dc0..0415bbb8 100644 --- a/AutoEvent/API/Enums/Effects.cs +++ b/AutoEvent/API/Enums/Effects.cs @@ -157,4 +157,23 @@ public enum StatusEffect /// Teleports the player to the pocket dimension and drains health until the player escapes or is killed. /// PocketCorroding, + + /// + /// The effect permit player to go trough door like Scp-106. + /// + Ghostly, + + /// + /// Effect given to player when being strangled by SCP-3114. + /// + Strangled, + OrangeCandy, + Spicy, + SugarCrave, + SugarHigh, + SugarRush, + TraumatizedByEvil, + Metal, + Prismatic, + SlowMetabolism, } \ No newline at end of file diff --git a/AutoEvent/API/Enums/LoadoutFlags.cs b/AutoEvent/API/Enums/LoadoutFlags.cs index 187775c0..0237e5a7 100644 --- a/AutoEvent/API/Enums/LoadoutFlags.cs +++ b/AutoEvent/API/Enums/LoadoutFlags.cs @@ -25,80 +25,80 @@ public enum LoadoutFlags /// No flags are specified. Loadouts will be applied normally. /// None = 0, - + /// /// Players will not have a role set. /// - IgnoreRole = 1, - + IgnoreRole = 1 << 0, // 1 + /// /// Players will not have items added. /// - IgnoreItems = 2, - + IgnoreItems = 1 << 1, // 2 + /// /// Players will not have their default role items cleared before adding items. /// - DontClearDefaultItems = 4, + DontClearDefaultItems = 1 << 2, // 4 /// /// Players won't have effects applied to them. /// - IgnoreEffects = 8, - + IgnoreEffects = 1 << 3, // 8 + /// /// Players won't have their health set. /// - IgnoreHealth = 16, - + IgnoreHealth = 1 << 4, // 16 + /// /// Player's won't have their Artificial Health set. /// - IgnoreAHP = 32, - + IgnoreAHP = 1 << 5, // 32 + /// /// Player's won't have their sizes changed. /// - IgnoreSize = 64, - + IgnoreSize = 1 << 6, // 64 + /// /// Player's won't have infinite ammo applied from loadouts. /// - IgnoreInfiniteAmmo = 128, - + IgnoreInfiniteAmmo = 1 << 7, // 128 + /// /// Players will have infinite ammo applied. Overrides IgnoreInfiniteAmmo. /// - ForceInfiniteAmmo = 256, - + ForceInfiniteAmmo = 1 << 8, // 256 + /// /// Players will note have Godmode set. /// - IgnoreGodMode = 512, - + IgnoreGodMode = 1 << 9, // 512 + /// /// Players will not recieve weapons. /// - IgnoreWeapons = 1024, - + IgnoreWeapons = 1 << 10, // 1024 + /// /// Stamina will not be added. /// - IgnoreStamina = 2048, - + IgnoreStamina = 1 << 11, // 2048, + /// /// The player will have an endless amount of ammo. /// - ForceEndlessClip = 4096, - + ForceEndlessClip = 1 << 12, // 4096, + /// /// The player will stay in the default spawn point. /// - UseDefaultSpawnPoint = 8192, + UseDefaultSpawnPoint = 1 << 13, //8192, /// /// Only give players items. /// - ItemsOnly = 16382, + ItemsOnly = (IgnoreStamina | IgnoreGodMode | IgnoreInfiniteAmmo | IgnoreSize | IgnoreAHP | IgnoreHealth | IgnoreStamina | IgnoreEffects | IgnoreRole), // None + ForceX // 16384 } diff --git a/AutoEvent/ActiveFeatures.cs b/AutoEvent/ActiveFeatures.cs new file mode 100644 index 00000000..3234f746 --- /dev/null +++ b/AutoEvent/ActiveFeatures.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: ActiveFeatures.cs +// Author: Redforce04#4091 +// Revision Date: 10/24/2023 10:20 PM +// Created Date: 10/24/2023 10:20 PM +// ----------------------------------------- + +using System; + +namespace AutoEvent; + +[Flags] +public enum ActiveFeatures +{ + None = 0, + Minigames20 = 1, + Lobby = 2, + Vote = 4, + Powerups = 8, + SchematicApi = 16, + BuildInfo = 32, + MinigameSpleef = 64, + InventoryMenuApi, + MinigamesGhostBusters, + All = ~0, +} \ No newline at end of file diff --git a/AutoEvent/AutoEvent.csproj b/AutoEvent/AutoEvent.csproj index 833cf5cf..d557e2b4 100644 --- a/AutoEvent/AutoEvent.csproj +++ b/AutoEvent/AutoEvent.csproj @@ -9,13 +9,14 @@ enable Release AnyCPU - 9.2.0 + false ..\bin\Release\Exiled TRACE;EXILED - true true + true + true x64 v4.8 512 @@ -55,11 +56,14 @@ - - - + + + + + + - + @@ -76,6 +80,9 @@ + + .gitignore + @@ -87,21 +94,38 @@ + + + + + + + + + + + + - - - - + + + + + + + + + \ No newline at end of file diff --git a/AutoEvent/AutoEvent.sln b/AutoEvent/AutoEvent.sln index 13707205..4c08b72b 100644 --- a/AutoEvent/AutoEvent.sln +++ b/AutoEvent/AutoEvent.sln @@ -9,6 +9,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchematicApi", "SchematicAp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerupApi", "PowerupApi\PowerupApi.csproj", "{1B07FE64-A112-499D-8A55-67EE912B1CB7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReplaceTextWithVariables", "ReplaceTextWithVariables\ReplaceTextWithVariables.csproj", "{2D16B95A-C579-4998-9E28-E26B077DC48B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InventoryMenu", "InventoryMenu\InventoryMenu.csproj", "{1F7DA672-31F6-45A7-B57E-3CC1A0D8DB2E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Release NWApi|Any CPU = Release NWApi|Any CPU @@ -19,14 +23,22 @@ Global {3C3FC008-22E1-4B28-BA50-A241B30CC216}.Release NWApi|Any CPU.Build.0 = Release NWApi|Any CPU {3C3FC008-22E1-4B28-BA50-A241B30CC216}.Release Exiled|Any CPU.ActiveCfg = Release EXILED|Any CPU {3C3FC008-22E1-4B28-BA50-A241B30CC216}.Release Exiled|Any CPU.Build.0 = Release EXILED|Any CPU - {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release NWApi|Any CPU.ActiveCfg = Release|Any CPU - {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release NWApi|Any CPU.Build.0 = Release|Any CPU {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release Exiled|Any CPU.ActiveCfg = Release|Any CPU {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release Exiled|Any CPU.Build.0 = Release|Any CPU - {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release NWApi|Any CPU.ActiveCfg = Release|Any CPU - {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release NWApi|Any CPU.Build.0 = Release|Any CPU + {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release NWApi|Any CPU.ActiveCfg = Release|Any CPU + {580DFED2-B2D7-4B89-B245-D60246BCFB79}.Release NWApi|Any CPU.Build.0 = Release|Any CPU {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release Exiled|Any CPU.ActiveCfg = Release|Any CPU {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release Exiled|Any CPU.Build.0 = Release|Any CPU + {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release NWApi|Any CPU.ActiveCfg = Release|Any CPU + {1B07FE64-A112-499D-8A55-67EE912B1CB7}.Release NWApi|Any CPU.Build.0 = Release|Any CPU + {2D16B95A-C579-4998-9E28-E26B077DC48B}.Release Exiled|Any CPU.ActiveCfg = Release|Any CPU + {2D16B95A-C579-4998-9E28-E26B077DC48B}.Release Exiled|Any CPU.Build.0 = Release|Any CPU + {2D16B95A-C579-4998-9E28-E26B077DC48B}.Release NWApi|Any CPU.ActiveCfg = Release|Any CPU + {2D16B95A-C579-4998-9E28-E26B077DC48B}.Release NWApi|Any CPU.Build.0 = Release|Any CPU + {1F7DA672-31F6-45A7-B57E-3CC1A0D8DB2E}.Release NWApi|Any CPU.ActiveCfg = Debug|Any CPU + {1F7DA672-31F6-45A7-B57E-3CC1A0D8DB2E}.Release NWApi|Any CPU.Build.0 = Debug|Any CPU + {1F7DA672-31F6-45A7-B57E-3CC1A0D8DB2E}.Release Exiled|Any CPU.ActiveCfg = Debug|Any CPU + {1F7DA672-31F6-45A7-B57E-3CC1A0D8DB2E}.Release Exiled|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AutoEvent/BlankVersionInfo.txt b/AutoEvent/BlankVersionInfo.txt new file mode 100644 index 00000000..4f095f90 --- /dev/null +++ b/AutoEvent/BlankVersionInfo.txt @@ -0,0 +1,80 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: VersionInfo.cs +// Author: Redforce04#4091 +// Revision Date: 08/02/2023 6:41 PM +// Created Date: 08/02/2023 6:41 PM +// ----------------------------------------- +/* + This file is apart of the building system. During building the following will happen: + - This file overwrites the ArgumentParser.cs + - The 3 variables notably identified by the "${}" will be replaced. + - This happens with another program called "ReplaceTextWithVariables" (found in project dir) + - This helps the program identify git tracking info for the auto-updater. + - Project is built + - Project is published for every architecture + - All builds are move to a /bin/Releases/export folder by default. + +*/ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Newtonsoft.Json; + +namespace AutoEvent; + +public class VersionInfo +{ + static VersionInfo() + { + Assemblies = JsonConvert.DeserializeObject>(BuildDependencies)?.AsReadOnly() ?? new List().AsReadOnly(); + } + public const string CommitHash = "{CI_COMMIT_SHORT_SHA}"; + public const string CommitBranch = "{CI_COMMIT_BRANCH}"; + public const string CommitVersion = "{CI_COMMIT_VERSION_TAG}"; + public const ActiveFeatures ActiveFeatures = global::AutoEvent.ActiveFeatures.All; + public const string BuildUser = "{BUILD_USER}"; + public static DateTime BuildTime { get; } = DateTime.Parse("{BUILD_DATE_TIME}"); + private const string BuildDependencies = "{BUILD_DEPENDENCIES}"; + internal static IReadOnlyList Assemblies { get; private set; } + public static IReadOnlyList Releases = new ReadOnlyCollection(new List() + { new ReleaseInfo("1.0.0", new Version(1,0,0), "1.0.0 Release", "Not Tracked", new DateTime(2023,2,28)), + new ReleaseInfo("1.0.1", new Version(1,0,1), "1.0.1 Release", "Not Tracked", new DateTime(2023, 3, 1)), + new ReleaseInfo("1.0.2", new Version(1,0,2), "1.0.2 Release", "Not Tracked", new DateTime(2023, 3, 2)), + new ReleaseInfo("1.0.3", new Version(1,0,3), "1.0.3 Release", "Not Tracked", new DateTime(2023, 3, 2)), + new ReleaseInfo("1.0.4", new Version(1,0,4), "1.0.4 Release", "Not Tracked", new DateTime(2023, 3, 3)), + new ReleaseInfo("1.0.5", new Version(1,0,5), "1.0.5 Release", "Not Tracked", new DateTime(2023, 3,3)), + new ReleaseInfo("1.0.6", new Version(1,0,6), "1.0.6 Release", "Not Tracked", new DateTime(2023, 3, 12)), + new ReleaseInfo("1.0.7", new Version(1,0,7), "1.0.7 Release", "Not Tracked", new DateTime(2023, 3, 12)), + new ReleaseInfo("7.0.0", new Version(7,0,0), "7.0.0 Release", "Not Tracked", new DateTime(2023, 3, 23)), + new ReleaseInfo("7.1.0", new Version(7,1,0), "7.1.0 Release", "Not Tracked", new DateTime(2023, 5, 31)), + new ReleaseInfo("7.2.0", new Version(7,2,0), "7.2.0 Release", "Not Tracked", new DateTime(2023, 6, 10)), + new ReleaseInfo("8.0.0", new Version(8,0,0), "8.0.0 Release", "Not Tracked", new DateTime(2023, 7, 8)), + new ReleaseInfo("8.0.1", new Version(8,0,1), "8.0.1 Release", "Not Tracked", new DateTime(2023, 7, 10)), + new ReleaseInfo("8.0.2", new Version(8,0,2), "8.0.2 Release", "Not Tracked", new DateTime(2023, 7, 10)), + new ReleaseInfo("8.1.0", new Version(8,1,0), "8.1.0 Release", "Not Tracked", new DateTime(2023, 7, 24)), + new ReleaseInfo("8.2.0", new Version(8,2,0), "8.2.0 Release", "Not Tracked", new DateTime(2023, 7, 28)), + new ReleaseInfo("8.2.1", new Version(8,2,1), "8.2.1 Release", "Not Tracked", new DateTime(2023, 7, 30)), + new ReleaseInfo("8.2.2", new Version(8,2,2), "8.2.2 Release", "Not Tracked", new DateTime(2023, 8, 2)), + new ReleaseInfo("8.2.4", new Version(8,2,4), "8.2.4 Release", "Not Tracked", new DateTime(2023, 8, 4)), + new ReleaseInfo("8.2.5", new Version(8,2,5), "8.2.5 Release", "Not Tracked", new DateTime(2023, 8, 5)), + new ReleaseInfo("8.2.6", new Version(8,2,6), "8.2.6 Release", "Not Tracked", new DateTime(2023, 8, 9)), + new ReleaseInfo("8.2.7", new Version(8,2,7), "8.2.7 Release", "Not Tracked", new DateTime(2023, 8, 16)), + new ReleaseInfo("8.2.7-NWApi", new Version(8,2,7), "8.2.7-NWApi Release", "Not Tracked", new DateTime(2023, 8, 27)), + new ReleaseInfo("8.2.8", new Version(8,2,8), "8.2.8 Release", "Not Tracked", new DateTime(2023, 8, 28)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,0), "9.1.0 Beta Release", "Initial 9.1.0 Beta Release", new DateTime(2023, 9, 21)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,2), "9.1.2 Beta Release", "Config Hotfix", new DateTime(2023, 9, 23)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,3), "9.1.3 Beta Release", "Events Hotfix", new DateTime(2023, 9, 24)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,4), "9.1.4 Beta Release", "Another Event Hotfix. More Config Options. Partial Config Validation", new DateTime(2023, 9, 25)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,5), "9.1.5 Beta Release", "Fixes Lighting Bugs. Config Hotfixes.", new DateTime(2023, 9, 26)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,6), "9.1.6 Beta Release", "Fixes Exiled translation bugs. Also fixes some events.", new DateTime(2023, 9, 27)), + new ReleaseInfo("9.1.0-beta", new Version(9,1,7), "9.1.7 Beta Release", "Adds Lobby and voting System", new DateTime(2023, 9, 28)), + new ReleaseInfo("9.1.8-beta", new Version(9,1,8), "9.1.8 Beta Release", "Fixes Bugs", new DateTime(2023, 9, 29)), + new ReleaseInfo("9.1.9-beta", new Version(9,1,9), "9.1.9 Beta Release", "More Bugs that are fixed. Minor Api Changes", new DateTime(2023, 10, 11)), + new ReleaseInfo("9.2.0", new Version(9,1,9), "9.2.0 Release - Reworked Backend", "Reworked backend for events. Added configs, events, reworked translations, reworked gameplay mechanics and much more. Official Release.", new DateTime(2023, 10, 22, 0, 31,0)), + }); +} \ No newline at end of file diff --git a/AutoEvent/Commands/BuildInfo.cs b/AutoEvent/Commands/BuildInfo.cs new file mode 100644 index 00000000..5dbbfd44 --- /dev/null +++ b/AutoEvent/Commands/BuildInfo.cs @@ -0,0 +1,160 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: BuildInfo.cs +// Author: Redforce04#4091 +// Revision Date: 10/24/2023 10:42 PM +// Created Date: 10/24/2023 10:42 PM +// ----------------------------------------- + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using CommandSystem; + +namespace AutoEvent.Commands; + +[CommandHandler(typeof(GameConsoleCommandHandler))] +[CommandHandler(typeof(RemoteAdminCommandHandler))] +[CommandHandler(typeof(ClientCommandHandler))] +public class BuildInfo : ICommand +{ + public bool Execute(ArraySegment arguments, ICommandSender sender, [UnscopedRef] out string response) + { + PermissionSystem.CheckPermission(sender, "ev.buildinfo.basic", out bool isConsole); + bool showBuildInfo = false; + bool showDependencies = false; + bool showFeatures = false; + bool showReleaseInfo = false; + if (arguments.Count >= 1) + { + for (int i = 0; i < arguments.Count; i++) + { + string arg = arguments.At(i).ToLower(); + bool subtract = arg.StartsWith("-"); + if (subtract) + arg = arg.Substring(1, arg.Length - 1); + switch (arg) + { + case "all" or "*": + // showDependencies = true; + showBuildInfo = true; + showReleaseInfo = true; + showFeatures = true; + break; + case "features" or "feats": + showFeatures = !subtract; + break; + case "dependencies" or "deps": + showDependencies = !subtract; + break; + case "buildinfo" or "build": + showBuildInfo = !subtract; + break; + case "releaseinfo" or "release": + showReleaseInfo = !subtract; + break; + } + } + } + + string colorAqua = isConsole ? "" : ""; + string colorOrange = isConsole ? "" : ""; + string colorYellow = isConsole ? "" : ""; + string colorpink = isConsole ? "" : ""; + string colorRed = isConsole ? "" : ""; + string colorGreen = isConsole ? "" : ""; + string colorBlue = isConsole ? "" : ""; + string colorLime = isConsole ? "" : ""; + string colorNickel = isConsole ? "" : ""; + string colorWhite = isConsole ? "" : ""; + string activeFeatures = ""; + if (showFeatures) + { + + activeFeatures = "Active Features:\n"; + foreach (Enum feature in Enum.GetValues(typeof(ActiveFeatures))) + { + if (feature is ActiveFeatures.None or ActiveFeatures.All) + continue; + + if (VersionInfo.ActiveFeatures.HasFlag(feature)) + { + activeFeatures += $" - {colorAqua}{feature}{colorWhite}\n"; + } + } + + activeFeatures += "\n"; + } + + var CurrentRelease = global::AutoEvent.VersionInfo.Releases.OrderByDescending(x => x.SemanticVersion).First(); + string releaseInfo = ""; + if (showReleaseInfo) + { + releaseInfo = + $"{CurrentRelease.Name} ({CurrentRelease.ReleaseDate.Month}/{CurrentRelease.ReleaseDate.Day}/{CurrentRelease.ReleaseDate.Year})\n" + + $"Changelog:\n" + + $"{CurrentRelease.ChangeLog}\n" + + $"\n"; + } + + string dependencyInfo = ""; + if (showDependencies) + { + dependencyInfo = "\nBuild Dependencies: \n"; + foreach (var x in VersionInfo.Assemblies) + { + dependencyInfo += $" - {x.Name} {(x.Version != "" ? $" (v{x.Version})" : "")} \n" + + $" - [Hash: {x.Hash}] \n"; + } + + dependencyInfo += "\n"; + } + string buildInfo = + $"{colorNickel}Build Info:\n" + + $" - Build Branch - {colorYellow}{VersionInfo.CommitBranch}{colorWhite} (Commit {colorpink}{VersionInfo.CommitHash}{colorNickel})\n" + + $" - Build Tag - {VersionInfo.CommitVersion}{colorNickel}\n" + + $" - Built by - {VersionInfo.BuildUser}\n" + + $" - Build Date - {VersionInfo.BuildTime.Month}/{VersionInfo.BuildTime.Day}/{VersionInfo.BuildTime.Year}\n"; + string versionString = + $"\nAuto Event Version - {colorAqua}{(CurrentRelease.Version)}{colorWhite}-{(Loader.IsExiledPlugin ? "Exiled" : "NWApi")}{(AutoEvent.BetaRelease ? $"{colorRed} [Beta]{colorWhite}" : "")}\n{colorWhite}" + + $"SL Version - {(DebugLogger.SLVersion)}\n" + + $"\n" + + $"{activeFeatures}" + + $"{releaseInfo}" + + $"{(showBuildInfo ? buildInfo : "")}" + + $"{dependencyInfo}"; + /* + * Auto Event Version - v9.2.0-NWApi [beta] + * SL Version 13.2.2-beta + * + * Active Features: + * - Minigames20 + * - Lobby + * - Vote + * - Powerups + * - SchematicApi + * - BuildInfo + * + * Release 9.7.3-beta (9/13/23) + * Changelog: + * 12345 cool things happened + * + * Build Info: + * - Build Branch - Main (Commit 0b38ec3) + * - Build Tag - 9.3.0 + * - Built By - Redforce04 + * - Build Date - 07/06/23 + + */ + response = versionString; + return true; + } + + public string Command => "ev"+ nameof(BuildInfo); + public string[] Aliases => new[] { "evinfo", "evbuild" }; + public string Description => $"Gets the info for the current build of AutoEvent and other important info."; +} diff --git a/AutoEvent/Commands/Debug/Debug.cs b/AutoEvent/Commands/Debug/Debug.cs index c8e23039..4bb80e88 100644 --- a/AutoEvent/Commands/Debug/Debug.cs +++ b/AutoEvent/Commands/Debug/Debug.cs @@ -39,6 +39,7 @@ public override void LoadGeneratedCommands() this.RegisterCommand(new SetRole()); this.RegisterCommand(new RNG()); this.RegisterCommand(new PowerupCommand()); + this.RegisterCommand(new MenuCommand()); } protected override bool ExecuteParent(ArraySegment arguments, ICommandSender sender, [UnscopedRef] out string response) diff --git a/AutoEvent/Commands/Debug/MenuCommand.cs b/AutoEvent/Commands/Debug/MenuCommand.cs new file mode 100644 index 00000000..4a61e46d --- /dev/null +++ b/AutoEvent/Commands/Debug/MenuCommand.cs @@ -0,0 +1,132 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: Menu.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 6:33 PM +// Created Date: 10/27/2023 6:33 PM +// ----------------------------------------- + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using AutoEvent.Interfaces; +using CommandSystem; +using InventoryMenu.API.Features; +using InventoryMenu.API; +using InventoryMenu; +using InventoryMenu.API.EventArgs; +using InventorySystem.Items.Firearms; +using InventorySystem.Items.Firearms.Attachments; +using MEC; +using PluginAPI.Core; +using Utils.NonAllocLINQ; + +namespace AutoEvent.Commands.Debug; + +public class MenuCommand : ICommand, IPermission +{ + public string Permission { get; set; } = "ev.debug"; + public string Command => "Menu"; + public bool Execute(ArraySegment arguments, ICommandSender sender, [UnscopedRef] out string response) + { + if (!sender.CheckPermission(Permission, out bool isConsole)) + { + response = "You don't have permission to use this command."; + return false; + } + + if (arguments.Count < 1) + { + response = "You must specify a player"; + return false; + } + var player = Player.GetPlayers().FirstOrDefault(ply => ply.Nickname.ToLower().Contains(arguments.At(0).ToLower())); + if (player is null) + { + response = $"Could not find player \"{arguments.At(0)}\""; + return false; + } + + if (arguments.Count >= 2 && arguments.At(1).ToLower() is "demo") + goto demo; + bool hide = arguments.Count >= 2 && arguments.At(1).ToLower() is "true" or "1" or "hide"; + bool canPickupItems = arguments.Count >= 3 && arguments.At(2).ToLower() is "true" or "1" or "pickup"; + if (hide) + { + player.HideMenu(); + response = $"Hid menu for player {player.Nickname}"; + return true; + } + + Menu menu = new Menu("Test menu.", canPickupItems); + menu.AddItem(new MenuItem(ItemType.Coin, "test coin", 0, OnRecieved)); + menu.AddItem(new MenuItem(ItemType.KeycardScientist, "test keycard", 1, OnRecieved)); + menu.AddItem(new MenuItem(ItemType.SCP018, "test ball", 2,OnRecieved)); + menu.AddItem(new MenuItem(ItemType.GrenadeHE, "test grenade", 3, OnRecieved)); + menu.AddItem(new MenuItem(ItemType.SCP330, "test candy", 4, OnRecieved)); + player.ShowMenu(menu); + + response = "Menu "; + return true; + demo: + Menu demo = new Menu("Test Menu.", false); + demo.AddItem(new MenuItem(ItemType.GunE11SR, "The AK Loadout.", 0, OnRecievedLoadout)); + demo.AddItem(new MenuItem(ItemType.GunLogicer, "The Logicer Loadout.", 1, OnRecievedLoadout)); + demo.AddItem(new MenuItem(ItemType.GunShotgun, "The Shotgun Loadout.", 2, OnRecievedLoadout)); + player.ShowMenu(demo); + player.SendBroadcast(demoBroadcast, 1200); + response = "Gave player demo menu selection."; + return true; + } + + private static string demoBroadcast = "Select a loadout in your inventory to spawn with."; + private static void OnRecievedLoadout(MenuItemClickedArgs ev) + { + if (!ev.IsLeftClick) + { + ushort bcDelay = 5; + ev.Player.ClearBroadcasts(); + ev.Player.SendBroadcast($"Loadout Option: {ev.MenuItemClicked.Description}", bcDelay); + Timing.CallDelayed(bcDelay, () => { ev.Player.SendBroadcast(demoBroadcast, 1200 );}); + return; + } + + switch (ev.MenuItemClicked.Item) + { + case ItemType.GunE11SR: + ev.Player.AddItem(ItemType.GunE11SR); + ev.Player.AddItem(ItemType.ArmorCombat); + ev.Player.AddItem(ItemType.Painkillers); + ev.Player.AddItem(ItemType.SCP207); + ev.Player.AddItem(ItemType.Medkit); + //weapon.ApplyAttachmentsCode((uint)AttachmentName.Flashlight); + break; + case ItemType.GunLogicer: + ev.Player.AddItem(ItemType.GunLogicer); + ev.Player.AddItem(ItemType.ArmorHeavy); + ev.Player.AddItem(ItemType.Medkit); + ev.Player.AddItem(ItemType.Painkillers); + break; + case ItemType.GunShotgun: + ev.Player.AddItem(ItemType.GunShotgun); + ev.Player.AddItem(ItemType.GunRevolver); + ev.Player.AddItem(ItemType.ArmorCombat); + ev.Player.AddItem(ItemType.GrenadeHE); + ev.Player.AddItem(ItemType.GrenadeHE); + ev.Player.AddItem(ItemType.Medkit); + break; + } + ev.Player.HideMenu(); + } + private static void OnRecieved(MenuItemClickedArgs ev) + { + DebugLogger.LogDebug($"{ev.MenuItemClicked.Item} [{(ev.IsLeftClick ? "Select" : "Drop")}]"); + } + + public string[] Aliases => Array.Empty(); + public string Description => "Provides a test menu to a player."; +} \ No newline at end of file diff --git a/AutoEvent/Commands/List.cs b/AutoEvent/Commands/List.cs index 9d76bddd..a6b73686 100644 --- a/AutoEvent/Commands/List.cs +++ b/AutoEvent/Commands/List.cs @@ -48,9 +48,9 @@ public bool Execute(ArraySegment arguments, ICommandSender sender, out s //{ "cedmod", new List() }, //{ "riptide", new List() }, }; - events["Internal Events"] = Event.Events.Where(ev => ev is IInternalEvent).OrderBy(x => x.Name).ToList(); - events["External Events"] = Event.Events.Where(ev => ev is not IInternalEvent && ev is not IExiledEvent).OrderBy(x => x.Name).ToList(); - events["Exiled Events"] = Event.Events.Where(ev => ev is IExiledEvent).OrderBy(x => x.Name).ToList(); + events["Internal Events"] = Event.Events.Where(ev => ev is IInternalEvent && ev is not IHiddenCommand).OrderBy(x => x.Name).ToList(); + events["External Events"] = Event.Events.Where(ev => ev is not IInternalEvent && ev is not IExiledEvent && ev is not IHiddenCommand).OrderBy(x => x.Name).ToList(); + events["Exiled Events"] = Event.Events.Where(ev => ev is IExiledEvent && ev is not IHiddenCommand).OrderBy(x => x.Name).ToList(); //events["cedmod"] = Event.Events.Where(ev => ev is IInternalEvent).OrderBy(x => x.Name).ToList(); // events["riptide"] = Event.Events.Where(ev => ev is IInternalEvent).OrderBy(x => x.Name).ToList(); foreach (KeyValuePair> eventlist in events) diff --git a/AutoEvent/Commands/MainCommand.cs b/AutoEvent/Commands/MainCommand.cs index ac05015c..d61b1354 100644 --- a/AutoEvent/Commands/MainCommand.cs +++ b/AutoEvent/Commands/MainCommand.cs @@ -20,9 +20,11 @@ public override void LoadGeneratedCommands() RegisterCommand(new List()); RegisterCommand(new Run()); RegisterCommand(new Stop()); + RegisterCommand(new BuildInfo()); //RegisterCommand(new Lobby()); //RegisterCommand(new Vote()); RegisterCommand(new Volume()); + RegisterCommand(new NoRestart()); RegisterCommand(new Reload.Reload()); RegisterCommand(new Debug.Debug()); RegisterCommand(new Config.Config()); diff --git a/AutoEvent/Commands/NoRestart.cs b/AutoEvent/Commands/NoRestart.cs new file mode 100644 index 00000000..6d593a30 --- /dev/null +++ b/AutoEvent/Commands/NoRestart.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: NoRestart.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 12:53 PM +// Created Date: 10/28/2023 12:53 PM +// ----------------------------------------- + +using System; +using System.Diagnostics.CodeAnalysis; +using AutoEvent.Interfaces; +using CommandSystem; +using Mirror; + +namespace AutoEvent.Commands; + +[CommandHandler(typeof(RemoteAdminCommandHandler))] +[CommandHandler(typeof(GameConsoleCommandHandler))] +public class NoRestart : ICommand, IPermission +{ + public bool Execute(ArraySegment arguments, ICommandSender sender, [UnscopedRef] out string response) + { + if (!sender.CheckPermission(Permission, out bool isConsole)) + { + response = "You do not have permission to run this command!"; + return false; + } + + if (!AutoEvent.Singleton.Config.RestartAfterRoundFinish) + { + response = + "Auto-Restart is not enabled on this server. To use this command, enable it in the AutoEvent Config."; + return false; + } + + string boldstart = isConsole ? "" : ""; + string boldend = isConsole ? "" : ""; + + bool enabled = DebugLogger.NoRestartEnabled; + if (arguments.Count >= 1) + { + if(arguments.At(0).ToLower() is "enable" or "enabled" or "true" or "1") + goto enable; + if(arguments.At(0).ToLower() is "disable" or "disabled" or "false" or "0") + goto disable; + } + + if (enabled) + goto disable; + + goto enable; + + enable: + DebugLogger.NoRestartEnabled = true; + response = + $"No-Restart has been enabled. The server will {boldstart}not{boldend} restart after the next event."; + return true; + disable: + DebugLogger.NoRestartEnabled = false; + response = $"No-Restart has been disabled. The server {boldstart}will{boldend} restart after the next event."; + return true; + } + + public string Command => nameof(NoRestart); + public string[] Aliases => Array.Empty(); + public string Description => "Disables auto-restarting the server after events are done."; + public string Permission { get; set; } = "ev.norestart"; +} \ No newline at end of file diff --git a/AutoEvent/Config.cs b/AutoEvent/Config.cs index 4f40d784..ae88b4c7 100644 --- a/AutoEvent/Config.cs +++ b/AutoEvent/Config.cs @@ -70,7 +70,13 @@ public Config() [Description("The players will be set once an event is done. **DO NOT USE A ROLE THAT IS ALSO IN IgnoredRoles**")] public RoleTypeId LobbyRole { get; set; } = RoleTypeId.ClassD; - + + [Description("If set to true, the server will do a restart 10 seconds after an event is done. The `ev norestart` will disable this.")] + public bool RestartAfterRoundFinish { get; set; } = false; + + [Description("The message that will be displayed when the server restarts.")] + public string ServerRestartMessage { get; set; } = "The server is restarting!"; + [Description("Where the configs directory is located. By default it is located in the AutoEvent folder.")] public string EventConfigsDirectoryPath { get; set; } diff --git a/AutoEvent/DebugLogger.cs b/AutoEvent/DebugLogger.cs index 11d3012f..e4acec8d 100644 --- a/AutoEvent/DebugLogger.cs +++ b/AutoEvent/DebugLogger.cs @@ -13,18 +13,28 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using MEC; using PluginAPI; using PluginAPI.Core; using PluginAPI.Helpers; +using PluginAPI.Loader; using UnityEngine; +using Version = GameCore.Version; namespace AutoEvent; public class DebugLogger { + static DebugLogger() + { + Assemblies = new List(); + } public static DebugLogger Singleton; - + internal static List Assemblies { get; set; } + internal static string SLVersion => GameCore.Version.VersionString; + public static bool NoRestartEnabled { get; set; } = false; + public const string Version = "9.2.2"; public DebugLogger(bool writeDirectly) { Singleton = this; @@ -50,39 +60,201 @@ public DebugLogger(bool writeDirectly) } File.Create(_filePath).Close(); - /*Timing.CallDelayed(5f, () => + Timing.CallDelayed(5f, () => { _getPlugins(); }); + } + } + catch (Exception e) + { + DebugLogger.LogDebug($"An error has occured while trying to create a debug log.", LogLevel.Warn, true); + DebugLogger.LogDebug($"{e}"); + } + } + + private void _getPlugins() + { + + string text = ""; + + text += $"Plugin Api Info: \n"; + // SLVersion = $"SCP SL Version: v{GameCore.Version.Major}.{GameCore.Version.Minor}.{GameCore.Version.Revision}, (Backwards Compatible: {GameCore.Version.BackwardCompatibility}, Backward Revision: {GameCore.Version.BackwardRevision})"; + text += $" {SLVersion}"; + text += $" Version: ({PluginApiVersion.Version}, {PluginApiVersion.VersionStatic}, {PluginApiVersion.VersionString})\n"; + text += $" VersionString: \n"; + text += $"NWApi Plugins Present: \n"; + text += _getNWApiPlugins(); + /*Plugins Present: + * MapEditorReborn.dll + * Assembly Hash: 142wesdvsdfsg + * Assembly Plugins: + * - MapEditorReborn by Micheal (v1.0.0) + */ + + + + text += "Exiled Plugins Present:\n"; + if (!Loader.isExiledPresent()) + text += $" Exiled Not Installed.\n"; + else + text += _getExiledPlugins(); + + File.AppendAllText(_filePath, text); + } + + private static string _getNWApiPlugins() + { + string text = ""; + try + { + + foreach (var keyValuePair in PluginAPI.Loader.AssemblyLoader.Plugins) + { + try + { + var version = keyValuePair.Key.GetCustomAttribute().InformationalVersion ?? ""; + AssemblyInfo info = new AssemblyInfo() + { + Name = keyValuePair.Key.GetName().ToString(), + Hash = keyValuePair.Key.ManifestModule.ModuleVersionId.ToString(), + Dependency = false, + Exiled = false, + Version = version + }; + var hashId = keyValuePair.Key.ManifestModule.ModuleVersionId; + text += $" {keyValuePair.Key.GetName()}"; + text += $" - Hash: {hashId}\n"; + foreach (var plugin in keyValuePair.Value) + { + info.Plugins.Add(new PluginInfo() + { + Name = plugin.Value.PluginName, ExiledPlugin = false, Authors = plugin.Value.PluginAuthor, + Version = plugin.Value.PluginVersion + }); + text += $" - Plugins:\n"; + text += $" - {plugin.Value.PluginName} by {plugin.Value.PluginAuthor} (v{plugin.Value.PluginVersion})\n"; + } + + Assemblies.Add(info); + } + catch + { + } + } + + text += "NWApi Dependencies Loaded:\n"; + foreach (var dependency in PluginAPI.Loader.AssemblyLoader.Dependencies) + { + try + { + if (dependency is null) + { + continue; + } + var version = dependency.GetCustomAttribute().InformationalVersion ?? ""; + + Assemblies.Add(new AssemblyInfo() + { + Name = dependency.GetName().ToString(), + Hash = dependency.ManifestModule.ModuleVersionId.ToString(), + Dependency = true, + Exiled = false, + Version = version + }); + text += $" {dependency.GetName()}\n"; + var hashId = dependency.ManifestModule.ModuleVersionId; + text += $" - Hash: {hashId}\n"; + } + catch { + } + } - string text = $"Plugin Api Info: \n" + - $" Version: {PluginApiVersion.Version}\n" + - $" VersionStatic: {PluginApiVersion.VersionStatic}\n" + - $" VersionString: {PluginApiVersion.VersionString}\n" + - $"Plugins Present: "; - /*Plugins Present: - * MapEditorReborn.dll (MapEditorReborn vX by Author) - * Assembly Hash: 142wesdvsdfsg - * - * - *//* - - foreach (var plugin in PluginAPI.Loader.AssemblyLoader.Plugins) + return text; + } + catch (Exception) + { + return ""; + } + + return ""; + } + private static string _getExiledPlugins() + { + try + { + string text = ""; + var plugins = Exiled.Loader.Loader.Plugins; + foreach (var plugin in plugins) + { + try + { + var version = plugin.Assembly.GetCustomAttribute().InformationalVersion ?? ""; + + AssemblyInfo info = new AssemblyInfo() { - var hashId = plugin.Key.ManifestModule.ModuleVersionId; + Name = plugin.Assembly.GetName().ToString(), + Hash = plugin.Assembly.ManifestModule.ModuleVersionId.ToString(), + Dependency = false, + Exiled = true, + Version = version, + }; + info.Plugins.Add(new PluginInfo() + { + ExiledPlugin = true, + Authors = plugin.Author, + Name = plugin.Name, + Version = plugin.Version.ToString(), + Descriptions = "", + }); + Assemblies.Add(info); + text += $" {plugin.Assembly.GetName()}\n"; + var hashId = plugin.Assembly.ManifestModule.ModuleVersionId; + text += $" - Hash: {hashId}\n"; + text += $" - Plugins:\n"; + text += $" {plugin.Name} by {plugin.Author} (v{plugin.Version})\n"; + } + catch(Exception e) + { + Log.Debug($"Couldn't find exiled plugins. Error: {e}"); + } + } - //text += $" {plugin.Key.FullName} {plugin.}"; - text += $" Assembly Hash: {hashId}"; + text += $"Exiled Dependencies Loaded: \n"; + foreach (var dependency in Exiled.Loader.Loader.Dependencies) + { + try + { + if (dependency is null) + { + continue; } - File.AppendAllText(_filePath,); - });*/ + var version = dependency.GetCustomAttribute().InformationalVersion ?? ""; + + AssemblyInfo info = new AssemblyInfo() + { + Name = dependency.GetName().ToString(), + Hash = dependency.ManifestModule.ModuleVersionId.ToString(), + Dependency = true, + Exiled = true, + Version = version + }; + Assemblies.Add(info); + text += $" {dependency.GetName()}\n"; + var hashId = dependency.ManifestModule.ModuleVersionId; + text += $" - Hash: {hashId}\n"; + } + catch(Exception e) + { + Log.Debug($"Couldn't find exiled dependencies. Error: {e}"); + } } } catch (Exception e) { - DebugLogger.LogDebug($"An error has occured while trying to create a debug log.", LogLevel.Warn, true); - DebugLogger.LogDebug($"{e}"); + return ""; } -} + return ""; + } private string _filePath; private static bool _loaded = false; public static bool Debug = false; @@ -154,4 +326,41 @@ public enum LogLevel Debug, Warn, Error, +} + + +internal struct AssemblyInfo +{ + public AssemblyInfo() + { + Plugins = new List(); + Exiled = false; + Dependency = false; + Name = ""; + Hash = ""; + Version = ""; + } + public bool Exiled { get; set; } + public bool Dependency { get; set; } + public string Name { get; set; } + public string Hash { get; set; } + public string Version { get; set; } + public List Plugins { get; set; } +} + +internal struct PluginInfo +{ + public PluginInfo() + { + ExiledPlugin = false; + Name = ""; + Version = ""; + Authors = ""; + Descriptions = ""; + } + public bool ExiledPlugin { get; set; } + public string Name { get; set; } + public string Version { get; set; } + public string Authors { get; set; } + public string Descriptions { get; set; } } \ No newline at end of file diff --git a/AutoEvent/Events/EventArgs/ShotEventArgs.cs b/AutoEvent/Events/EventArgs/ShotEventArgs.cs new file mode 100644 index 00000000..32bbdbf5 --- /dev/null +++ b/AutoEvent/Events/EventArgs/ShotEventArgs.cs @@ -0,0 +1,86 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +using PluginAPI.Core; +using UnityEngine; + +namespace AutoEvent.Events.EventArgs +{ + /// + /// Contains all information after a player has fired a weapon. + /// + public class ShotEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// The hit. + /// + /// + /// + /// + /// + /// + public ShotEventArgs(Player shooter, RaycastHit hit, IDestructible destructible, float damage) + { + Player = shooter; + Damage = damage; + Distance = hit.distance; + Position = hit.point; + RaycastHit = hit; + + if (destructible is HitboxIdentity identity) + { + Hitbox = identity; + Target = Player.Get(Hitbox.TargetHub); + } + } + + /// + /// Gets the target of the shot. Can be !. + /// + public Player Target { get; } + + /// + /// Gets the hitbox type of the shot. Can be !. + /// + public HitboxIdentity Hitbox { get; } + + /// + /// Gets the shot distance. + /// + public float Distance { get; } + + /// + /// Gets the shot position. + /// + public Vector3 Position { get; } + + /// + /// Gets the raycast result. + /// + public RaycastHit RaycastHit { get; } + + /// + /// Gets or sets the inflicted damage. + /// + public float Damage { get; set; } + + /// + /// Gets or sets a value indicating whether or not the shot can hurt the target. + /// + public bool CanHurt { get; set; } = true; + + /// + /// Gets the player who shot. + /// + public Player Player { get; } + } +} \ No newline at end of file diff --git a/AutoEvent/Events/Handlers/Players.cs b/AutoEvent/Events/Handlers/Players.cs index 27e3f6f9..fd1e8e46 100644 --- a/AutoEvent/Events/Handlers/Players.cs +++ b/AutoEvent/Events/Handlers/Players.cs @@ -15,6 +15,7 @@ internal class Players public static event Action PlayerNoclip; public static event Action SwingingJailbird; public static event Action ChargingJailbird; + public static event Action Shot; public static void OnDropAmmo(DropAmmoArgs ev) => DropAmmo?.Invoke(ev); public static void OnDropItem(DropItemArgs ev) => DropItem?.Invoke(ev); public static void OnPlaceTantrum(PlaceTantrumArgs ev) => PlaceTantrum?.Invoke(ev); @@ -25,5 +26,6 @@ internal class Players public static void OnPlayerNoclip(PlayerNoclipArgs ev) => PlayerNoclip?.Invoke(ev); public static void OnSwingingJailbird(SwingingJailbirdEventArgs ev) => SwingingJailbird?.Invoke(ev); public static void OnChargingJailbird(ChargingJailbirdEventArgs ev) => ChargingJailbird?.Invoke(ev); + public static void OnShot(ShotEventArgs ev) => Shot?.Invoke(ev); } } diff --git a/AutoEvent/FodyWeavers.xml b/AutoEvent/FodyWeavers.xml index 447bbee0..e0f5c8fe 100644 --- a/AutoEvent/FodyWeavers.xml +++ b/AutoEvent/FodyWeavers.xml @@ -9,6 +9,7 @@ NVorbis PowerupApi SchematicApi + InventoryMenu diff --git a/AutoEvent/FriendlyFireSystem.cs b/AutoEvent/FriendlyFireSystem.cs index ffda4f93..6ad4898d 100644 --- a/AutoEvent/FriendlyFireSystem.cs +++ b/AutoEvent/FriendlyFireSystem.cs @@ -38,7 +38,7 @@ private static void initializeFFSettings() } else DebugLogger.LogDebug("CedMod has not been detected."); - } + } public static bool FriendlyFireDetectorIsDisabled { get diff --git a/AutoEvent/Games/Battle/Configs/Config.cs b/AutoEvent/Games/Battle/Configs/Config.cs index f077b160..e5cbe0a1 100644 --- a/AutoEvent/Games/Battle/Configs/Config.cs +++ b/AutoEvent/Games/Battle/Configs/Config.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using AutoEvent.API; using AutoEvent.Interfaces; diff --git a/AutoEvent/Games/Battle/Plugin.cs b/AutoEvent/Games/Battle/Plugin.cs index 66da4538..0a3b6a6a 100644 --- a/AutoEvent/Games/Battle/Plugin.cs +++ b/AutoEvent/Games/Battle/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventMap, IEventSound, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.BattleTranslate.BattleDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.BattleTranslate.BattleCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); // Map Info can be inherited as long as the event inherits IEventMap. // MapInfo.Map is the Schematic Object for the map. diff --git a/AutoEvent/Games/Boss/Plugin.cs b/AutoEvent/Games/Boss/Plugin.cs index 36d1ae95..da823840 100644 --- a/AutoEvent/Games/Boss/Plugin.cs +++ b/AutoEvent/Games/Boss/Plugin.cs @@ -21,6 +21,8 @@ public class Plugin : Event, IEventMap, IEventSound, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.BossTranslate.BossDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.BossTranslate.BossCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); + public MapInfo MapInfo { get; set; } = new MapInfo() { MapName = "DeathParty", Position = new Vector3(6f, 1030f, -43.5f) }; diff --git a/AutoEvent/Games/DeathParty/Plugin.cs b/AutoEvent/Games/DeathParty/Plugin.cs index 8a245df3..e894ef5c 100644 --- a/AutoEvent/Games/DeathParty/Plugin.cs +++ b/AutoEvent/Games/DeathParty/Plugin.cs @@ -23,6 +23,7 @@ public class Plugin : Event, IEventMap, IEventSound, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.DeathTranslate.DeathDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.DeathTranslate.DeathCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); public MapInfo MapInfo { get; set; } = new MapInfo() {MapName = "DeathParty", Position = new Vector3(10f, 1012f, -40f), }; public SoundInfo SoundInfo { get; set; } = new SoundInfo() diff --git a/AutoEvent/Games/Deathmatch/Plugin.cs b/AutoEvent/Games/Deathmatch/Plugin.cs index 0361a324..1918f8fa 100644 --- a/AutoEvent/Games/Deathmatch/Plugin.cs +++ b/AutoEvent/Games/Deathmatch/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventMap, IEventSound, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.DeathmatchTranslate.DeathmatchDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.DeathmatchTranslate.DeathmatchCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public DeathmatchConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Escape/Plugin.cs b/AutoEvent/Games/Escape/Plugin.cs index 29cdcecb..535b4d47 100644 --- a/AutoEvent/Games/Escape/Plugin.cs +++ b/AutoEvent/Games/Escape/Plugin.cs @@ -21,6 +21,7 @@ public class Plugin : Event, IEventSound, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.EscapeTranslate.EscapeDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.EscapeTranslate.EscapeCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public EscapeConfig Config { get; set; } public SoundInfo SoundInfo { get; set; } = diff --git a/AutoEvent/Games/Example/ExampleEvent.cs b/AutoEvent/Games/Example/ExampleEvent.cs index 419fec50..fb06c298 100644 --- a/AutoEvent/Games/Example/ExampleEvent.cs +++ b/AutoEvent/Games/Example/ExampleEvent.cs @@ -36,6 +36,7 @@ public class ExampleEvent : Event, IEventMap, IEventSound, IInternalEvent public override string Description { get; set; } = "An example event based on the battle event."; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = "example"; + public override Version Version { get; set; } = new Version(1, 0, 0); // Make sure you set this to true. Otherwise you must register your plugin via Exiled or NWApi manually. // Add the event to AutoEvent.Events to manually register it. diff --git a/AutoEvent/Games/FallDown/Plugin.cs b/AutoEvent/Games/FallDown/Plugin.cs index dd431417..668dde8c 100644 --- a/AutoEvent/Games/FallDown/Plugin.cs +++ b/AutoEvent/Games/FallDown/Plugin.cs @@ -21,6 +21,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.FallTranslate.FallDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.FallTranslate.FallCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public FallDownConfig Config { get; set; } = null; [EventConfig] public FallDownConfig Warning => FallDownConfigPresets.PlatformWarning(); public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/FinishWay/Plugin.cs b/AutoEvent/Games/FinishWay/Plugin.cs index 4f8be8a4..84a0afd3 100644 --- a/AutoEvent/Games/FinishWay/Plugin.cs +++ b/AutoEvent/Games/FinishWay/Plugin.cs @@ -20,6 +20,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.FinishWayTranslate.FinishWayDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.FinishWayTranslate.FinishWayCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public FinishWayConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Football/Plugin.cs b/AutoEvent/Games/Football/Plugin.cs index ce5e989f..631e43c1 100644 --- a/AutoEvent/Games/Football/Plugin.cs +++ b/AutoEvent/Games/Football/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.FootballTranslate.FootballDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.FootballTranslate.FootballCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public FootballConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() {MapName = "Football", Position = new Vector3(76f, 1026.5f, -43.68f), }; diff --git a/AutoEvent/Games/GhostBusters/Configs/GhostBustersConfig.cs b/AutoEvent/Games/GhostBusters/Configs/GhostBustersConfig.cs new file mode 100644 index 00000000..85b792fc --- /dev/null +++ b/AutoEvent/Games/GhostBusters/Configs/GhostBustersConfig.cs @@ -0,0 +1,94 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: GhostBustersConfig.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 2:05 AM +// Created Date: 10/28/2023 2:05 AM +// ----------------------------------------- + +using System.Collections.Generic; +using System.ComponentModel; +using AutoEvent.API; +using AutoEvent.API.Enums; +using AutoEvent.Interfaces; +using PlayerRoles; + +namespace AutoEvent.Games.GhostBusters.Configs; + +public class GhostBustersConfig : EventConfig +{ + [Description("How much time the hunters have to kill the ghosts until ghosts can kill them.")] + public int TimeUntilMidnightInSeconds { get; set; } = 180; + + [Description("How much time the ghosts have to kill the hunters, after midnight hits.")] + public int MidnightDurationInSeconds { get; set; } = 120; + + public RoleCount HunterCount { get; set; } = new RoleCount(2, 4, 20); + + public List GhostLoadouts { get; set; } = new List() + { + new Loadout() + { + Roles = new Dictionary() + { + { RoleTypeId.Scientist, 100 } + }, + Effects = new List() + { + new Effect() + { + EffectType = StatusEffect.Ghostly + }, + }, + } + }; + public Loadout SniperLoadout { get; set; } = new Loadout() + { + Roles = new Dictionary() + { + { RoleTypeId.ChaosRifleman, 100 } + }, + Items = new List() + { + ItemType.ParticleDisruptor + }, + Health = 2000, + }; + public Loadout TankLoadout { get; set; } = new Loadout() + { + Roles = new Dictionary() + { + { RoleTypeId.ChaosMarauder, 100 } + }, + Items = new List() + { + ItemType.MicroHID + }, + Health = 2000, + }; + public Loadout MeleeLoadout { get; set; } = new Loadout() + { + Roles = new Dictionary() + { + { RoleTypeId.ChaosRifleman, 100 } + }, + Items = new List() + { + ItemType.Jailbird, + }, + Effects = new List() + { + new Effect() + { + EffectType = StatusEffect.MovementBoost, + Intensity = 20, + } + }, + Health = 2000, + }; + +} \ No newline at end of file diff --git a/AutoEvent/Games/GhostBusters/Configs/Translation.cs b/AutoEvent/Games/GhostBusters/Configs/Translation.cs new file mode 100644 index 00000000..fba1bfb0 --- /dev/null +++ b/AutoEvent/Games/GhostBusters/Configs/Translation.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: Translation.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 1:52 AM +// Created Date: 10/28/2023 1:52 AM +// ----------------------------------------- + +using Exiled.API.Interfaces; + +namespace AutoEvent.Games.GhostBusters.Configs; + + +#if EXILED +public class GhostBustersTranslate : ITranslation +#else + public class GhostBustersTranslate +#endif +{ + public string GhostBustersCommandName { get; set; } = "ghosts"; // Soccer in america - football everywhere else 🦅🦅🦅🇺🇸🇺🇸🇺🇸 <- (USA Flag doesnt render in rider...) + public string GhostBustersName { get; set; } = "Ghost Busters"; // Soccer in america - football everywhere else 🦅🦅🦅🇺🇸🇺🇸🇺🇸 <- (USA Flag doesnt render in rider...) + public string GhostBustersDescription { get; set; } = "Ghostbusters vs ghosts. The clock is ticking, will the ghost-busters be able to kill all ghosts before midnight hits?"; + public string GhostBustersStartGhostMessage { get; set; } = "You're a Ghost!\nRun and Hide from the Ghost Busters! They will try and take you out! \nYou can pickup powerups and use them in the inventory menu."; + public string GhostBustersStartHunterMessage { get; set; } = "You're a Ghost-Buster!\nFind all the ghosts before it is too late!\nYou can select a role in your inventory menu."; + public string GhostBustersMidnightGhostMessage { get; set; } = "Midnight Has Hit\nFind and kill the Ghost Busters!"; + public string GhostBustersMidnightHunterMessage { get; set; } = "Midnight Has Hit\nRun and hide for your life! The ghosts are after you!"; + public string GhostBustersGhostsWin { get; set; } = "Ghost Win\nThe ghosts have killed all hunters."; + public string GhostBustersHuntersWin { get; set; } = "Ghost-Buster Win\nThe Ghost-Busters have exterminated all of the ghosts."; + } \ No newline at end of file diff --git a/AutoEvent/Games/GhostBusters/EventHandler.cs b/AutoEvent/Games/GhostBusters/EventHandler.cs new file mode 100644 index 00000000..589ebed2 --- /dev/null +++ b/AutoEvent/Games/GhostBusters/EventHandler.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: EventHandlers.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 1:51 AM +// Created Date: 10/28/2023 1:51 AM +// ----------------------------------------- + +using AutoEvent.Events.EventArgs; + +namespace AutoEvent.Games.GhostBusters; + +public class EventHandler +{ + private Plugin _plugin { get; set; } + public EventHandler(Plugin plugin) + { + _plugin = plugin; + } + public void OnTeamRespawn(TeamRespawnArgs ev) => ev.IsAllowed = false; + public void OnSpawnRagdoll(SpawnRagdollArgs ev) => ev.IsAllowed = false; + public void OnPlaceBullet(PlaceBulletArgs ev) => ev.IsAllowed = false; + public void OnPlaceBlood(PlaceBloodArgs ev) => ev.IsAllowed = false; + public void OnDropItem(DropItemArgs ev) => ev.IsAllowed = false; + public void OnDropAmmo(DropAmmoArgs ev) => ev.IsAllowed = false; +} \ No newline at end of file diff --git a/AutoEvent/Games/GhostBusters/Plugin.cs b/AutoEvent/Games/GhostBusters/Plugin.cs new file mode 100644 index 00000000..5c369d0b --- /dev/null +++ b/AutoEvent/Games/GhostBusters/Plugin.cs @@ -0,0 +1,201 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: Plugin.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 1:50 AM +// Created Date: 10/28/2023 1:50 AM +// ----------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using AutoEvent.Events.Handlers; +using AutoEvent.Games.GhostBusters.Configs; +using AutoEvent.Games.Infection; +using AutoEvent.Interfaces; +using CustomPlayerEffects; +using Interactables.Interobjects.DoorUtils; +using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventoryMenu.API.Features; +using MapGeneration; +using MEC; +using PlayerRoles; +using PluginAPI.Core; +using PluginAPI.Events; +using Powerups.Extensions; +using UnityEngine; +using Event = AutoEvent.Interfaces.Event; + +namespace AutoEvent.Games.GhostBusters; + +public class Plugin : Event, IEventSound, IInternalEvent + { + public override string Name { get; set; } = AutoEvent.Singleton.Translation.GhostBustersTranslate.GhostBustersName; + public override string Description { get; set; } = AutoEvent.Singleton.Translation.GhostBustersTranslate.GhostBustersDescription; + public override string Author { get; set; } = "Redforce04 and Riptide"; + public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.GhostBustersTranslate.GhostBustersCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); + [EventConfig] public GhostBustersConfig Config { get; set; } + public SoundInfo SoundInfo { get; set; } = new SoundInfo() + { SoundName = "Ghostbusters.ogg", Volume = 5, Loop = true }; + protected override float PostRoundDelay { get; set; } = 10f; + protected override float FrameDelayInSeconds { get; set; } = 1f; + private EventHandler EventHandler { get; set; } + private GhostBustersTranslate Translation { get; set; } = AutoEvent.Singleton.Translation.GhostBustersTranslate; + private TimeSpan _remainingTime; + internal Menu HunterRoleMenu { get; set; } + internal Menu GhostRoleMenu { get; set; } + internal Menu GhostPowerupMenu { get; set; } + + public enum Stage { Prep, PreMidnight, Midnight } + protected override void RegisterEvents() + { + + EventHandler = new EventHandler(this); + EventManager.RegisterEvents(EventHandler); + Servers.TeamRespawn += EventHandler.OnTeamRespawn; + Servers.SpawnRagdoll += EventHandler.OnSpawnRagdoll; + Servers.PlaceBullet += EventHandler.OnPlaceBullet; + Servers.PlaceBlood += EventHandler.OnPlaceBlood; + Players.DropItem += EventHandler.OnDropItem; + Players.DropAmmo += EventHandler.OnDropAmmo; + } + + protected override void UnregisterEvents() + { + EventManager.UnregisterEvents(EventHandler); + Servers.TeamRespawn -= EventHandler.OnTeamRespawn; + Servers.SpawnRagdoll -= EventHandler.OnSpawnRagdoll; + Servers.PlaceBullet -= EventHandler.OnPlaceBullet; + Servers.PlaceBlood -= EventHandler.OnPlaceBlood; + Players.DropItem -= EventHandler.OnDropItem; + Players.DropAmmo -= EventHandler.OnDropAmmo; + + EventHandler = null; + } + protected override void OnStart() + { + Extensions.JailbirdIsInvincible = true; + HunterRoleMenu = new Menu("Available Roles. Right click to view more details, left click to select the role.", false); + HunterRoleMenu.AddItem(new MenuItem(ItemType.MicroHID, "Tank Loadout", 0, HuntersSelectLoadout)); + HunterRoleMenu.AddItem(new MenuItem(ItemType.ParticleDisruptor, "Sniper Loadout", 1, HuntersSelectLoadout)); + HunterRoleMenu.AddItem(new MenuItem(ItemType.Jailbird, "Melee Loadout", 2, HuntersSelectLoadout)); + GhostRoleMenu = new Menu("Available Roles. Right click to view more details, left click to select the role.", true); + GhostPowerupMenu = new Menu("Powerup Menu", true); + GhostPowerupMenu.AddItem(new MenuItem(ItemType.Medkit, "Heal", 0)); + GhostPowerupMenu.AddItem(new MenuItem(ItemType.SCP268, "", 0)); + GhostPowerupMenu.AddItem(new MenuItem(ItemType.SCP018, "", 0)); + _remainingTime = new TimeSpan(0,0,Config.TimeUntilMidnightInSeconds); + var hunters = Config.HunterCount.GetPlayers(true); + foreach(Player ply in Player.GetPlayers()) + { + if (hunters.Contains(ply)) + SetHunter(ply); + else + SetGhost(ply); + } + + } + + public void ProcessGetMenuArgs(GetMenuItemsForPlayerArgs ev) + { + + } + + private void HuntersSelectLoadout(MenuItemClickedArgs ev) + { + switch (ev.MenuItemClicked.Item) + { + case ItemType.MicroHID: + ev.Player.GiveLoadout(Config.TankLoadout); + break; + case ItemType.ParticleDisruptor: + ev.Player.GiveLoadout(Config.SniperLoadout); + break; + case ItemType.Jailbird: + ev.Player.GiveLoadout(Config.MeleeLoadout); + if(ev.Player.EffectsManager.GetEffect()?.Intensity > 0) + ev.Player.ApplyFakeEffect(1); + break; + } + ev.Player.HideMenu(); + + Timing.CallDelayed(0.1f, () => + { + ev.Player.CurrentItem = ev.Player.Items.First(x => x.ItemTypeId.IsWeapon()); + }); + + } + + private void SetHunter(Player ply) + { + ply.ClearBroadcasts(); + ply.SendBroadcast(Translation.GhostBustersStartHunterMessage, 15); + ply.SetRole(RoleTypeId.Scp049, RoleChangeReason.Respawn, RoleSpawnFlags.UseSpawnpoint); + Timing.CallDelayed(0.25f, () => + { + ply.SetRole(RoleTypeId.ChaosConscript, RoleChangeReason.Respawn, RoleSpawnFlags.None); + }); + ply.ShowMenu(HunterRoleMenu); + + } + + private void SetGhost(Player ply) + { + ply.ClearBroadcasts(); + ply.SendBroadcast(Translation.GhostBustersStartGhostMessage, 15); + ply.GiveLoadout(Config.GhostLoadouts); + ply.ShowMenu(GhostPowerupMenu); + } + + protected override IEnumerator BroadcastStartCountdown() + { + for (float _time = 15; _time > 0; _time--) + { + //Extensions.Broadcast(Translation.Replace("{time}", $"{_time}"), 1); + + yield return Timing.WaitForSeconds(1f); + EventTime += TimeSpan.FromSeconds(1f); + } + } + + protected override bool IsRoundDone() + { + return true; + } + + protected override void ProcessFrame() + { + var time = $"{_remainingTime.Minutes:00}:{_remainingTime.Seconds:00}"; + foreach (Player player in Player.GetPlayers()) + { + //player.SendBroadcast(""); + } + + //var a = PluginAPI.Core.Map.Rooms.First(x => x.Name == RoomName.HczCheckpointA); + //var b = PluginAPI.Core.Map.Rooms.First(x => x.Name == RoomName.HczCheckpointB); + //a.ApiRoom + //var nameTag = a.gameObject.GetComponentInChildren().TargetDoor.ServerChangeLock() ? name.GetName : null; + + _remainingTime -= TimeSpan.FromSeconds(FrameDelayInSeconds); + } + + protected override void OnFinished() + { + int ghosts = Player.GetPlayers().Count(x => !x.HasLoadout(Config.MeleeLoadout) && !x.HasLoadout(Config.SniperLoadout) && + !x.HasLoadout(Config.TankLoadout)); + if (ghosts > 0) + { + Map.Broadcast(10, Translation.GhostBustersGhostsWin); + } + else + { + Map.Broadcast(10, Translation.GhostBustersHuntersWin); + } + } + } \ No newline at end of file diff --git a/AutoEvent/Games/Glass/Features/PlatformSelector.cs b/AutoEvent/Games/Glass/Features/PlatformSelector.cs index 931d7049..6ca7e46a 100644 --- a/AutoEvent/Games/Glass/Features/PlatformSelector.cs +++ b/AutoEvent/Games/Glass/Features/PlatformSelector.cs @@ -16,6 +16,7 @@ using AutoEvent.Games.Infection; using HarmonyLib; using UnityEngine; +using Random = UnityEngine.Random; namespace AutoEvent.Games.Glass.Features; @@ -60,9 +61,9 @@ private void _selectPlatformSideCount() switch (_seedMethod) { case SeedMethod.UnityRandom: - Random.InitState(seedInt); - leftSidePriority = Random.Range(0, 2) == 1; - percent = Random.Range((int)MinimumSideOffset, (int)MaximumSideOffset); + UnityEngine.Random.InitState(seedInt); + leftSidePriority = UnityEngine.Random.Range(0, 2) == 1; + percent = UnityEngine.Random.Range((int)MinimumSideOffset, (int)MaximumSideOffset); break; case SeedMethod.SystemRandom: var random = new System.Random(seedInt); diff --git a/AutoEvent/Games/Glass/Plugin.cs b/AutoEvent/Games/Glass/Plugin.cs index 544951aa..7dddc7ca 100644 --- a/AutoEvent/Games/Glass/Plugin.cs +++ b/AutoEvent/Games/Glass/Plugin.cs @@ -28,6 +28,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.GlassTranslate.GlassDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.GlassTranslate.GlassCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public GlassConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() {MapName = "Glass", Position = new Vector3(76f, 1026.5f, -43.68f) }; diff --git a/AutoEvent/Games/GunGame/Plugin.cs b/AutoEvent/Games/GunGame/Plugin.cs index 5e6fbad8..2848419b 100644 --- a/AutoEvent/Games/GunGame/Plugin.cs +++ b/AutoEvent/Games/GunGame/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.GunGameTranslate.GunGameDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.GunGameTranslate.GunGameCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public GunGameConfig Config { get; set; } diff --git a/AutoEvent/Games/HideAndSeek/Plugin.cs b/AutoEvent/Games/HideAndSeek/Plugin.cs index a13d63c1..886bc7cf 100644 --- a/AutoEvent/Games/HideAndSeek/Plugin.cs +++ b/AutoEvent/Games/HideAndSeek/Plugin.cs @@ -25,6 +25,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.HideTranslate.HideDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.HideTranslate.HideCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public HideAndSeekConfig Config { get; set; } diff --git a/AutoEvent/Games/Infection/Plugin.cs b/AutoEvent/Games/Infection/Plugin.cs index 47e6df45..7ee7addc 100644 --- a/AutoEvent/Games/Infection/Plugin.cs +++ b/AutoEvent/Games/Infection/Plugin.cs @@ -19,6 +19,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.InfectTranslate.ZombieDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.InfectTranslate.ZombieCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public InfectConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() { MapName = "Zombie", Position = new Vector3(115.5f, 1030f, -43.5f), MapRotation = Quaternion.identity }; diff --git a/AutoEvent/Games/Jail/Plugin.cs b/AutoEvent/Games/Jail/Plugin.cs index a7285a93..a3057ecf 100644 --- a/AutoEvent/Games/Jail/Plugin.cs +++ b/AutoEvent/Games/Jail/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.JailTranslate.JailDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.JailTranslate.JailCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public JailConfig Config { get; set; } [EventConfigPreset] public JailConfig AdminEvent => JailConfigPresets.AdminEvent; diff --git a/AutoEvent/Games/Knives/Plugin.cs b/AutoEvent/Games/Knives/Plugin.cs index ad00d0a9..7d456fe8 100644 --- a/AutoEvent/Games/Knives/Plugin.cs +++ b/AutoEvent/Games/Knives/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.KnivesTranslate.KnivesDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.KnivesTranslate.KnivesCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public KnivesConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Lava/Plugin.cs b/AutoEvent/Games/Lava/Plugin.cs index 6506bcb0..b0c60c27 100644 --- a/AutoEvent/Games/Lava/Plugin.cs +++ b/AutoEvent/Games/Lava/Plugin.cs @@ -26,6 +26,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.LavaTranslate.LavaDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.LavaTranslate.LavaCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public LavaConfig Config { get; set; } diff --git a/AutoEvent/Games/Line/Plugin.cs b/AutoEvent/Games/Line/Plugin.cs index 2ef29f36..203c2ed7 100644 --- a/AutoEvent/Games/Line/Plugin.cs +++ b/AutoEvent/Games/Line/Plugin.cs @@ -21,6 +21,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.LineTranslate.LineDescription; public override string Author { get; set; } = "Logic_Gun"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.LineTranslate.LineCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public LineConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Lobby/Plugin.cs b/AutoEvent/Games/Lobby/Plugin.cs index 80ee5e1b..310adb0b 100644 --- a/AutoEvent/Games/Lobby/Plugin.cs +++ b/AutoEvent/Games/Lobby/Plugin.cs @@ -4,6 +4,7 @@ using AutoEvent.Interfaces; using UnityEngine; using System.Linq; +using CommandSystem; using Event = AutoEvent.Interfaces.Event; using Player = PluginAPI.Core.Player; using PluginAPI.Core; @@ -11,12 +12,13 @@ namespace AutoEvent.Games.Lobby { - public class Plugin : Event, IEventMap, IEventSound, IHidden, IVote + public class Plugin : Event, IEventMap, IEventSound, IInternalEvent, IHiddenCommand { public override string Name { get; set; } = "Lobby"; public override string Description { get; set; } = "A lobby in which one quick player chooses a mini-game."; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = "lobby"; + public override Version Version { get; set; } = new Version(1, 0, 0); public SoundInfo SoundInfo { get; set; } = new SoundInfo() { SoundName = "FireSale.ogg", Volume = 10, Loop = false }; public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Puzzle/Plugin.cs b/AutoEvent/Games/Puzzle/Plugin.cs index 2e459092..fc8b3bbd 100644 --- a/AutoEvent/Games/Puzzle/Plugin.cs +++ b/AutoEvent/Games/Puzzle/Plugin.cs @@ -24,6 +24,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.PuzzleTranslate.PuzzleDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.PuzzleTranslate.PuzzleCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public PuzzleConfig Config { get; set; } diff --git a/AutoEvent/Games/Spleef/Configs/SpleefConfig.cs b/AutoEvent/Games/Spleef/Configs/SpleefConfig.cs new file mode 100644 index 00000000..71221c72 --- /dev/null +++ b/AutoEvent/Games/Spleef/Configs/SpleefConfig.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: SpleefConfig.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:20 PM +// Created Date: 10/17/2023 6:20 PM +// ----------------------------------------- + +using System.Collections.Generic; +using System.ComponentModel; +using AutoEvent.API; +using AutoEvent.Interfaces; +using PlayerRoles; + +namespace AutoEvent.Games.Spleef.Configs; + +public class SpleefConfig : EventConfig +{ + [Description("How long the round should last.")] + public int RoundDurationInSeconds { get; set; } = 300; + + [Description("Set to -1 to disable. Causes platforms to regenerate after a certain number of seconds.")] + public int RegeneratePlatformsAfterXSeconds { get; set; } = -1; + + [Description("How many platforms on the x and y axis. Total Platforms = PlatformAxisCount * PlatformAxisCount * LayerCount. Size is automatically determined.")] + public int PlatformAxisCount { get; set; } = 20; + [Description("How many \"levels\" of height should be in the map. ")] + public int LayerCount { get; set; } = 3; + + [Description("How long before platforms will fall after being stepped on. Set to -1 to disable this.")] + public float PlatformFallDelay { get; set; } = -1; + + [Description("The amount of health platforms have. Set to -1 to make them invincible.")] + public float PlatformHealth { get; set; } = 1; + + [Description("A list of loadouts for spleef.")] + public List PlayerLoadouts { get; set; } = new List() + { + new Loadout() + { + Roles = new Dictionary() + { + { RoleTypeId.ClassD, 100 }, + }, + Items = new List() + { + ItemType.GunCOM15, + }, + InfiniteAmmo = AmmoMode.InfiniteAmmo + } + }; +} \ No newline at end of file diff --git a/AutoEvent/Games/Spleef/Configs/SpleefTranslation.cs b/AutoEvent/Games/Spleef/Configs/SpleefTranslation.cs new file mode 100644 index 00000000..b6782dd3 --- /dev/null +++ b/AutoEvent/Games/Spleef/Configs/SpleefTranslation.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: SpleefTranslation.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:20 PM +// Created Date: 10/17/2023 6:20 PM +// ----------------------------------------- + +namespace AutoEvent.Games.Spleef.Configs; + +public class SpleefTranslation +{ + public string SpleefCommandName { get; set; } = "spleef"; + public string SpleefName { get; set; } = "Spleef"; + public string SpleefDescription { get; set; } = "Shoot at or run over the platforms before you fall into the void! (Try shooting platforms under people)"; + public string SpleefStart { get; set; } = "Starts in: {time}"; + public string SpleefRunning { get; set; } = "Players Alive: {players}\nTime remaining: {remaining}"; + public string SpleefAllDied { get; set; } = "All players died\nMini-game ended"; + public string SpleefSeveralSurvivors { get; set; } = "Several people survived\nMini-game ended"; + public string SpleefWinner { get; set; } = "Winner: {winner}\nMini-game ended"; + public string SpleefDied { get; set; } = "Burned in Lava"; +} \ No newline at end of file diff --git a/AutoEvent/Games/Spleef/EventHandler.cs b/AutoEvent/Games/Spleef/EventHandler.cs new file mode 100644 index 00000000..2b49772b --- /dev/null +++ b/AutoEvent/Games/Spleef/EventHandler.cs @@ -0,0 +1,64 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: EventHandler.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:20 PM +// Created Date: 10/17/2023 6:20 PM +// ----------------------------------------- + +using System; +using AutoEvent.API.Components; +using AutoEvent.Events.EventArgs; +using AutoEvent.Games.Spleef.Features; +using InventorySystem.Items.Armor; +using InventorySystem.Items.Firearms; +using InventorySystem.Items.Firearms.Modules; +using PlayerStatsSystem; +using PluginAPI.Core.Attributes; +using PluginAPI.Enums; +using PluginAPI.Events; +using UnityEngine; + +namespace AutoEvent.Games.Spleef; + +public class EventHandler +{ + private Plugin _plugin { get; set; } + public EventHandler(Plugin plugin) + { + _plugin = plugin; + } + public void OnShot(ShotEventArgs ev) + { + if (_plugin.Config.PlatformHealth < 0) + { + return; + } + + if (ev.Player.CurrentItem is not Firearm firearm) + { + return; + } + if (ev.Damage <= 0) + { + ev.Damage = BodyArmorUtils.ProcessDamage(0, firearm.BaseStats.DamageAtDistance(firearm, ev.Distance), Mathf.RoundToInt(firearm.ArmorPenetration * 100f)); + } + ev.RaycastHit.collider.transform.GetComponentsInParent().ForEach(x => + { + var damageHandler = new FirearmDamageHandler(ev.Player.CurrentItem as Firearm, ev.Damage, false); + bool result = x.Damage(ev.Damage, damageHandler, ev.RaycastHit.point); + }); + } + + + public void OnTeamRespawn(TeamRespawnArgs ev) => ev.IsAllowed = false; + public void OnSpawnRagdoll(SpawnRagdollArgs ev) => ev.IsAllowed = false; + public void OnPlaceBullet(PlaceBulletArgs ev) => ev.IsAllowed = false; + public void OnPlaceBlood(PlaceBloodArgs ev) => ev.IsAllowed = false; + public void OnDropItem(DropItemArgs ev) => ev.IsAllowed = false; + public void OnDropAmmo(DropAmmoArgs ev) => ev.IsAllowed = false; +} \ No newline at end of file diff --git a/AutoEvent/Games/Spleef/Features/FallPlatformComponent.cs b/AutoEvent/Games/Spleef/Features/FallPlatformComponent.cs new file mode 100644 index 00000000..68495980 --- /dev/null +++ b/AutoEvent/Games/Spleef/Features/FallPlatformComponent.cs @@ -0,0 +1,128 @@ +using System; +using AdminToys; +using AutoEvent.API.Components; +using MEC; +using Mirror; +using PlayerStatsSystem; +using PluginAPI.Core; +using UnityEngine; + +namespace AutoEvent.Games.Spleef.Features +{ + public class FallPlatformComponent : MonoBehaviour, IDestructible + { + private BoxCollider collider; + + public float RegenerationDelay { get; set; } = -1; + public float FallDelay { get; set; } = -1; + private float Scale { get; set; } + public void Init(float regenerationDelay = 0, float fallDelay = -1, float health = 1, float fallStartDelay = 15f, float scale = 1f) + { + Scale = scale; + RegenerationDelay = regenerationDelay; + FallDelay = fallDelay; + Health = health; + DefaultHealth = health; + Timing.CallDelayed(fallStartDelay, () => + { + collider.isTrigger = true; + }); + } + private void Start() + { + collider = gameObject.AddComponent(); + collider.isTrigger = false; + var val = gameObject.GetComponent().NetworkScale + new Vector3(0.2f, 4f, 0.2f);// * Scale; + collider.size = val; + + //DebugLogger.LogDebug($"Size: {val}"); + // new Vector3(1, 10, 1); + } + void OnTriggerEnter(Collider other) + { + if (Player.Get(other.gameObject) is Player) + { + + if (FallDelay < 0) + return; + if (isDestroyed) + return; + this.GetComponent().NetworkMaterialColor = Color.red; + //Destroy(gameObject); + Timing.CallDelayed(FallDelay, () => { DestroyThis(); }); + } + } + + private void DestroyThis() + { + isDestroyed = true; + this.GetComponent().NetworkMaterialColor = Color.red; + gameObject.transform.position += Vector3.down * 25; + Health = -1000; + NetworkServer.UnSpawn(this.gameObject); + NetworkServer.Spawn(this.gameObject); + if (RegenerationDelay > 0) + { + Timing.CallDelayed(RegenerationDelay, () => + { + RestoreThis(); + }); + } + } + + private void RestoreThis() + { + isDestroyed = false; + this.GetComponent().NetworkMaterialColor = Color.green; + gameObject.transform.position += Vector3.up * 25; + Health = DefaultHealth; + NetworkServer.UnSpawn(this.gameObject); + NetworkServer.Spawn(this.gameObject); + } + + public bool Damage(float damage, DamageHandlerBase handler, Vector3 exactHitPos) + { + if (isDestroyed) + { + return false; + } + Health -= damage; + if (Health <= 0) + { + DestroyThis(); + } + + return true; + } + + private bool isDestroyed = false; + public uint NetworkId { get; } + public Vector3 CenterOfMass { get; } + public float Health { get; private set; } + private float DefaultHealth { get; set; } + public event Action DamagingPrimitive; + + /* + public bool Damage(float damage, DamageHandlerBase handler, Vector3 exactHitPos) + { + var ev = new DamagingPrimitiveArgs(damage, handler, exactHitPos); + DamagingPrimitive?.Invoke(ev); + if (!ev.IsAllowed) + { + return false; + } + + Health -= ev.Damage; + if (Health <= 0) + { + + var prim = gameObject.GetComponent(); + NetworkServer.UnSpawn(base.gameObject); + Destroy(gameObject); + } + + return true; + } + */ + } +} diff --git a/AutoEvent/Games/Spleef/Features/RandomClass.cs b/AutoEvent/Games/Spleef/Features/RandomClass.cs new file mode 100644 index 00000000..d4eb35e1 --- /dev/null +++ b/AutoEvent/Games/Spleef/Features/RandomClass.cs @@ -0,0 +1,14 @@ +using System.Linq; +using MER.Lite.Objects; +using UnityEngine; + +namespace AutoEvent.Games.Spleef +{ + internal class RandomClass + { + public static Vector3 GetSpawnPosition(SchematicObject GameMap) + { + return GameMap.AttachedBlocks.Where(x => x.name == "Spawnpoint").FirstOrDefault().transform.position; + } + } +} diff --git a/AutoEvent/Games/Spleef/Features/SpleefPlatform.cs b/AutoEvent/Games/Spleef/Features/SpleefPlatform.cs new file mode 100644 index 00000000..089bcd8c --- /dev/null +++ b/AutoEvent/Games/Spleef/Features/SpleefPlatform.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: SpleefPlatform.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:38 PM +// Created Date: 10/17/2023 6:38 PM +// ----------------------------------------- + +using UnityEngine; + +namespace AutoEvent.Games.Spleef; + +public class SpleefPlatform +{ + public SpleefPlatform(float sizeX, float sizeY, float sizeZ, float positionX, float positionY, float positionZ) + { + X = sizeX; + Y = sizeY; + Z = sizeZ; + PositionX = positionX; + PositionY = positionY; + PositionZ = positionZ; + } + + public GameObject GameObject { get; set; } + public ushort PlatformId { get; set; } + public float X { get; set; } + public float Y { get; set; } + public float Z { get; set; } + public float PositionX { get; set; } + public float PositionY { get; set; } + public float PositionZ { get; set; } +} \ No newline at end of file diff --git a/AutoEvent/Games/Spleef/Plugin.cs b/AutoEvent/Games/Spleef/Plugin.cs new file mode 100644 index 00000000..15d22943 --- /dev/null +++ b/AutoEvent/Games/Spleef/Plugin.cs @@ -0,0 +1,247 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: Plugin.cs +// Author: Redforce04#4091 +// Revision Date: 10/17/2023 6:20 PM +// Created Date: 10/17/2023 6:20 PM +// ----------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using AdminToys; +using AutoEvent.API.Components; +using AutoEvent.API.Enums; +using AutoEvent.Events.Handlers; +using AutoEvent.Games.FallDown; +using AutoEvent.Games.Spleef.Configs; +using AutoEvent.Games.Spleef.Features; +using AutoEvent.Interfaces; +using CommandSystem.Commands.RemoteAdmin; +using InventorySystem.Items.Usables; +using MEC; +using Mirror; +using PluginAPI.Core; +using PluginAPI.Events; +using UnityEngine; +using Utils.NonAllocLINQ; +using Event = AutoEvent.Interfaces.Event; + +namespace AutoEvent.Games.Spleef; + +public class Plugin : Event, IEventMap, IEventSound +{ + public override string Name { get; set; } = AutoEvent.Singleton.Translation.SpleefTranslate.SpleefName; + public override string Description { get; set; } = AutoEvent.Singleton.Translation.SpleefTranslate.SpleefDescription; + public override string Author { get; set; } = "Redforce04"; + public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.SpleefTranslate.SpleefCommandName; + public override Version Version { get; set; } = new Version(1, 0, 1); + public SpleefTranslation Translation { get; set; } = AutoEvent.Singleton.Translation.SpleefTranslate; + + [EventConfig] + public SpleefConfig Config { get; set; } + public EventHandler EventHandler { get; set; } + public MapInfo MapInfo { get; set; } = new MapInfo() + { MapName = "Puzzle", Position = new Vector3(76f, 1026.5f, -43.68f), }; + public SoundInfo SoundInfo { get; set; } = new SoundInfo() + { SoundName = "Puzzle.ogg", Volume = 15, Loop = true }; + + /// + /// A local list of platforms that changes round to round. + /// + private List _listPlatforms; + + private List _colorIndicators; + private float _spawnHeight; + private TimeSpan _remaining; + + /// + /// All platforms in the map. + /// + private Dictionary _platforms; + private GameObject _lava; + + protected override void RegisterEvents() + { + EventHandler = new EventHandler(this); + Servers.TeamRespawn += EventHandler.OnTeamRespawn; + Servers.SpawnRagdoll += EventHandler.OnSpawnRagdoll; + Servers.PlaceBullet += EventHandler.OnPlaceBullet; + Servers.PlaceBlood += EventHandler.OnPlaceBlood; + Players.DropItem += EventHandler.OnDropItem; + Players.DropAmmo += EventHandler.OnDropAmmo; + Players.Shot += EventHandler.OnShot; + EventManager.RegisterEvents(EventHandler); + + } + + protected override void UnregisterEvents() + { + EventManager.UnregisterEvents(EventHandler); + Servers.TeamRespawn -= EventHandler.OnTeamRespawn; + Servers.SpawnRagdoll -= EventHandler.OnSpawnRagdoll; + Servers.PlaceBullet -= EventHandler.OnPlaceBullet; + Servers.PlaceBlood -= EventHandler.OnPlaceBlood; + Players.DropItem -= EventHandler.OnDropItem; + Players.DropAmmo -= EventHandler.OnDropAmmo; + Players.Shot -= EventHandler.OnShot; + EventHandler = null; + } + + protected override void OnStart() + { + _remaining = TimeSpan.FromSeconds(Config.RoundDurationInSeconds); + _platforms = new Dictionary(); + _lava = MapInfo.Map.AttachedBlocks.First(x => x.name == "Lava"); + _lava.AddComponent(); + _colorIndicators = MapInfo.Map.AttachedBlocks.Where(x => x.name == "Cube").ToList(); + GeneratePlatforms(Config.PlatformAxisCount); + foreach (Player player in Player.GetPlayers()) + { + player.Position = RandomClass.GetSpawnPosition(MapInfo.Map); + } + foreach (Player ply in Player.GetPlayers()) + { + ply.GiveLoadout(Config.PlayerLoadouts, LoadoutFlags.IgnoreWeapons); + ply.Position = MapInfo.Position + new Vector3(0,Config.LayerCount * 3f + 5,0); + } + } + private void GeneratePlatforms(int amountPerAxis = 5) + { + + float areaSizeX = 20f; + float areaSizeY = 20f; + float sizeX = areaSizeX / amountPerAxis; + float sizeY = areaSizeY / amountPerAxis; + float startPosX = -(areaSizeX/2f) + sizeX / 2f; + float startPosY = -(areaSizeY/2f) + sizeY / 2f; + float startPosZ = 6f; + float breakSize = .2f; + float sizeZ = 3f; + _spawnHeight = 6f; + List platforms = new List(); + for (int z = 0; z < Config.LayerCount; z++) + { + for (int x = 0; x < amountPerAxis; x++) + { + for (int y = 0; y < amountPerAxis; y++) + { + float posX = startPosX + (sizeX * x); + float posY = startPosY + (sizeY * y); + float posZ = startPosZ + (sizeZ * z); + var plat = new SpleefPlatform(sizeX - breakSize, sizeY - breakSize, .3f, posX, posY, posZ); + platforms.Add(plat); + if (posZ > _spawnHeight + 2) + { + _spawnHeight = posZ + 2; + } + } + } + } + + var primary = MapInfo.Map.AttachedBlocks.FirstOrDefault(x => x.name == "Platform"); + foreach(var plat in MapInfo.Map.AttachedBlocks.Where(x => x.name == "Platform")) + { + if (plat.GetInstanceID() != primary.GetInstanceID()) + GameObject.Destroy(plat); + } + + ushort id = 0; + foreach (SpleefPlatform platform in platforms) + { + + Vector3 position = MapInfo.Map.Position + new Vector3(platform.PositionX, platform.PositionZ ,platform.PositionY); + var newPlatform = GameObject.Instantiate(primary, position, Quaternion.identity); + _platforms.Add(id, newPlatform); + + try + { + var component = newPlatform.AddComponent(); + component.Init(Config.RegeneratePlatformsAfterXSeconds, Config.PlatformFallDelay, Config.PlatformHealth, 15); + // component.DamagingPrimitive += OnDamage; + } + catch (Exception e) + { + DebugLogger.LogDebug($"Exception \n{e}"); + } + + var prim = newPlatform.GetComponent() ?? newPlatform.AddComponent(); + prim.NetworkMaterialColor = Color.green; + + prim.Position = position; + prim.NetworkPosition = position; + prim.transform.position = position; + prim.transform.localPosition = position; + prim.Scale = new Vector3(platform.X , platform.Z, platform.Y); + prim.NetworkScale = new Vector3(platform.X , platform.Z, platform.Y); + prim.PrimitiveType = PrimitiveType.Cube; + prim.transform.localScale = new Vector3(platform.X, platform.Z, platform.Y); + NetworkServer.UnSpawn(newPlatform); + NetworkServer.Spawn(newPlatform); + id++; + } + GameObject.Destroy(primary); + } + + + protected override IEnumerator BroadcastStartCountdown() + { + for (int time = 15; time > 0; time--) + { + Extensions.Broadcast($"{Translation.SpleefDescription}\n{Translation.SpleefStart.Replace("{time}", $"{time}")}", 1); + yield return Timing.WaitForSeconds(1f); + } + } + + protected override void CountdownFinished() + { + foreach (Player ply in Player.GetPlayers()) + { + ply.GiveLoadout(Config.PlayerLoadouts, LoadoutFlags.ItemsOnly); + } + } + + protected override bool IsRoundDone() + { + return !(Player.GetPlayers().Count(ply => ply.IsAlive) > 1) && EventTime.TotalSeconds < Config.RoundDurationInSeconds; + } + protected override void ProcessFrame() + { + int count = Player.GetPlayers().Count(x => x.IsAlive); + foreach (Player ply in Player.GetPlayers()) + { + ply.SendBroadcast(Translation.SpleefRunning.Replace("{players}", count.ToString()).Replace("{remaining}", $"{_remaining.Minutes:00}:{_remaining.Seconds:00}"), (ushort)this.FrameDelayInSeconds); + } + _remaining -= TimeSpan.FromSeconds(FrameDelayInSeconds); + } + + protected override void OnFinished() + { + int count = Player.GetPlayers().Count(x => x.IsAlive); + if (count > 1) + { + Server.SendBroadcast(Translation.SpleefSeveralSurvivors, 10); + } + else if (count == 1) + { + Server.SendBroadcast(Translation.SpleefWinner.Replace("{winner}", Player.GetPlayers().First(x => x.IsAlive).Nickname), 10); + } + else + { + Server.SendBroadcast(Translation.SpleefAllDied, 10); + } + } + + protected override void OnCleanup() + { + foreach (var x in this._platforms) + { + GameObject.Destroy(x.Value); + } + base.OnCleanup(); + } +} \ No newline at end of file diff --git a/AutoEvent/Games/Survival/Plugin.cs b/AutoEvent/Games/Survival/Plugin.cs index 4d313343..548596d4 100644 --- a/AutoEvent/Games/Survival/Plugin.cs +++ b/AutoEvent/Games/Survival/Plugin.cs @@ -21,6 +21,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.SurvivalTranslate.SurvivalDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.SurvivalTranslate.SurvivalCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public SurvivalConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Versus/Plugin.cs b/AutoEvent/Games/Versus/Plugin.cs index 70c44f4b..db72aa73 100644 --- a/AutoEvent/Games/Versus/Plugin.cs +++ b/AutoEvent/Games/Versus/Plugin.cs @@ -22,6 +22,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.VersusTranslate.VersusDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.VersusTranslate.VersusCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public VersusConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Games/Vote/Plugin.cs b/AutoEvent/Games/Vote/Plugin.cs index aac84fe7..4592f6a0 100644 --- a/AutoEvent/Games/Vote/Plugin.cs +++ b/AutoEvent/Games/Vote/Plugin.cs @@ -1,4 +1,5 @@ -using PlayerRoles; +using System; +using PlayerRoles; using PluginAPI.Events; using System.Collections.Generic; using System.Linq; @@ -6,17 +7,19 @@ using AutoEvent.Events.Handlers; using MEC; using PluginAPI.Core; +using CommandSystem; using Event = AutoEvent.Interfaces.Event; using Player = PluginAPI.Core.Player; namespace AutoEvent.Games.Vote { - public class Plugin : Event, IEventSound, IHidden, IVote + public class Plugin : Event, IEventSound, IInternalEvent, IHiddenCommand { public override string Name { get; set; } = "Vote"; public override string Description { get; set; } = "Start voting for the mini-game."; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = "vote"; + public override Version Version { get; set; } = new Version(1, 0, 0); public SoundInfo SoundInfo { get; set; } = new SoundInfo() { SoundName = "FireSale.ogg", Volume = 10, Loop = false }; private EventHandler EventHandler { get; set; } diff --git a/AutoEvent/Games/ZombieEscape/Plugin.cs b/AutoEvent/Games/ZombieEscape/Plugin.cs index 250508bc..aea823a0 100644 --- a/AutoEvent/Games/ZombieEscape/Plugin.cs +++ b/AutoEvent/Games/ZombieEscape/Plugin.cs @@ -25,6 +25,7 @@ public class Plugin : Event, IEventSound, IEventMap, IInternalEvent public override string Description { get; set; } = AutoEvent.Singleton.Translation.ZombieEscapeTranslate.ZombieEscapeDescription; public override string Author { get; set; } = "KoT0XleB"; public override string CommandName { get; set; } = AutoEvent.Singleton.Translation.ZombieEscapeTranslate.ZombieEscapeCommandName; + public override Version Version { get; set; } = new Version(1, 0, 0); [EventConfig] public ZombieEscapeConfig Config { get; set; } public MapInfo MapInfo { get; set; } = new MapInfo() diff --git a/AutoEvent/Interfaces/Event.cs b/AutoEvent/Interfaces/Event.cs index bceb0e0d..bd5bbc26 100644 --- a/AutoEvent/Interfaces/Event.cs +++ b/AutoEvent/Interfaces/Event.cs @@ -12,6 +12,7 @@ using MEC; using UnityEngine; using YamlDotNet.Core; +using Version = System.Version; namespace AutoEvent.Interfaces { @@ -135,6 +136,8 @@ private static bool TryGetEventByCName(string type, out Event ev) /// The name of the map that is used to run the map via command. /// public abstract string CommandName { get; set; } + + public abstract Version Version { get; set; } #endregion #region Event Settings // Settings that event authors can define to modify the abstracted implementations /// diff --git a/AutoEvent/Interfaces/EventConfig.cs b/AutoEvent/Interfaces/EventConfig.cs index e1011bfe..b4b80a8d 100644 --- a/AutoEvent/Interfaces/EventConfig.cs +++ b/AutoEvent/Interfaces/EventConfig.cs @@ -10,6 +10,7 @@ // Created Date: 09/13/2023 3:32 PM // ----------------------------------------- +using System; using System.Collections.Generic; using System.ComponentModel; using AutoEvent.API.Enums; @@ -40,6 +41,9 @@ public EventConfig() [Description("Should this plugin output debug logs.")] public bool Debug { get; set; } + + [Description("DO NOT CHANGE THIS. IT WILL BREAK THINGS. AutoEvent will automatically manage this setting.")] + public virtual Version ConfigVersion { get; set; } } public class MapChance { diff --git a/AutoEvent/InventoryMenu/API/EventArgs/GetMenuItemsForPlayerArgs.cs b/AutoEvent/InventoryMenu/API/EventArgs/GetMenuItemsForPlayerArgs.cs new file mode 100644 index 00000000..350bc3f3 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/EventArgs/GetMenuItemsForPlayerArgs.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: GetMenuItemsForPlayerArgs.cs +// Author: Redforce04#4091 +// Revision Date: 10/28/2023 3:16 PM +// Created Date: 10/28/2023 3:16 PM +// ----------------------------------------- + +using InventoryMenu.API.Features; +using InventorySystem.Items; +using PluginAPI.Core; + +namespace InventoryMenu.API.EventArgs; + +public class GetMenuItemsForPlayerArgs +{ + public GetMenuItemsForPlayerArgs(Player ply, Menu menu, Dictionary? items = null) + { + Player = ply; + Menu = menu; + if (items is null) + { + Items = Menu._itemBases; + } + } + public Player Player { get; private set; } + public Menu Menu { get; private set; } + public Dictionary Items { get; set; } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/EventArgs/MenuItemClickedArgs.cs b/AutoEvent/InventoryMenu/API/EventArgs/MenuItemClickedArgs.cs new file mode 100644 index 00000000..6f061221 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/EventArgs/MenuItemClickedArgs.cs @@ -0,0 +1,36 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: MenuItemClickedArgs.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 2:12 PM +// Created Date: 10/27/2023 2:12 PM +// ----------------------------------------- + +using InventoryMenu.API.Features; +using PluginAPI.Core; + +namespace InventoryMenu.API.EventArgs; + +public class MenuItemClickedArgs +{ + public MenuItemClickedArgs(Player player, MenuItem menuItemClicked, bool isLeftClick, bool isAllowed = true) + { + if (menuItemClicked is null) + { + Log.Warn("Menu item clicked was null. This is an error!"); + return; + } + Player = player; + MenuItemClicked = menuItemClicked; + IsLeftClick = isLeftClick; + IsAllowed = isAllowed; + } + public Player Player { get; private set; } + public MenuItem MenuItemClicked { get; private set; } + public bool IsLeftClick { get; set; } + public bool IsAllowed { get; set; } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Extensions.cs b/AutoEvent/InventoryMenu/API/Extensions.cs new file mode 100644 index 00000000..decf1b7b --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Extensions.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: Extensions.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 3:17 PM +// Created Date: 10/27/2023 3:17 PM +// ----------------------------------------- + +using InventoryMenu.API.Features; +using PluginAPI.Core; + +namespace InventoryMenu.API; + +public static class Extensions +{ + public static void ShowMenu(this Player ply, Menu menu) => menu.ShowToPlayer(ply); + public static void HideMenu(this Player ply) + { + var instance = MenuManager.Menus.FirstOrDefault(x => x.CanPlayerSee(ply)); + + if (instance is null) + return; + + instance.HideForPlayer(ply); + } + +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Features/Broadcast.cs b/AutoEvent/InventoryMenu/API/Features/Broadcast.cs new file mode 100644 index 00000000..5a446007 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Features/Broadcast.cs @@ -0,0 +1,280 @@ +/* + * Taken from Riptide Events. Thanks Riptide! + */ +using System.Diagnostics; +using MEC; +using PluginAPI.Core; + +namespace InventoryMenu.API.Features +{ + public enum BroadcastPriority { Lowest, VeryLow, Low, Medium, High, VeryHigh, Highest }; + + public sealed class BroadcastOverride + { + static BroadcastOverride() + { + } + + class BroadcastInfo + { + class Line + { + public int size = 44; + public BroadcastPriority priority = BroadcastPriority.Lowest; + public float duration = -1.0f; + public string msg = ""; + } + + List lines = new List(); + Stopwatch stop_watch = new Stopwatch(); + bool dirty = false; + CoroutineHandle handle = new CoroutineHandle(); + + public BroadcastInfo() + { + stop_watch.Start(); + } + + public void SetEvenLineSizes(int line_count) + { + UpdateDuration(); + + List sizes = new List { 178, 89, 59, 44, 35, 29, 25, 22, 19, 17, 16, 14, 12, 11 }; + int dif = line_count - lines.Count; + for (int i = 0; i < dif; i++) + lines.Add(new Line()); + + if (lines.Count > line_count) + lines.RemoveRange(line_count, lines.Count - line_count); + + foreach (Line line in lines) + line.size = sizes[line_count - 1]; + + dirty = true; + } + + public void SetCustomLineSizes(IEnumerable sizes) + { + UpdateDuration(); + + int dif = sizes.Count() - lines.Count; + for (int i = 0; i < dif; i++) + lines.Add(new Line()); + + if (lines.Count > sizes.Count()) + lines.RemoveRange(sizes.Count(), lines.Count - sizes.Count()); + + for (int i = 0; i < sizes.Count(); i++) + lines[i].size = sizes.ElementAt(i); + + dirty = true; + } + + public void BroadcastLine(int line, float duration, BroadcastPriority priority, string msg) + { + if (line >= 1 && line <= lines.Count) + { + if (lines[line - 1].duration <= 0.0f || lines[line - 1].priority <= priority) + { + UpdateDuration(); + lines[line - 1].priority = priority; + lines[line - 1].duration = duration; + lines[line - 1].msg = msg; + dirty = true; + } + } + } + + public void ClearLines(BroadcastPriority priority) + { + UpdateDuration(); + + foreach (Line line in lines) + if (line.priority <= priority) + line.duration = -1.0f; + + dirty = true; + } + + public void ClearLine(int line, BroadcastPriority priority) + { + if (line >= 1 && line <= lines.Count) + { + if (lines[line - 1].priority <= priority) + { + UpdateDuration(); + lines[line - 1].duration = -1.0f; + dirty = true; + } + } + } + + public void UpdateDuration() + { + float delta = (float)stop_watch.Elapsed.TotalSeconds; + stop_watch.Restart(); + + foreach (Line line in lines) + line.duration -= delta; + } + + public float Update(Player player, float delta) + { + UpdateDuration(); + + string msg = ""; + foreach (Line line in lines) + { + if (line.duration > 0.0f) + msg += "" + line.msg + "\n"; + //else + // msg += " \n"; + } + + player.SendBroadcast(msg, 300, Broadcast.BroadcastFlags.Truncated, true); + + float min = 300.0f; + bool any_active = false; + foreach (Line line in lines) + { + if (line.duration > 0.0f) + { + min = Math.Min(min, line.duration); + any_active = true; + } + } + if (any_active) + return min; + else + return -1.0f; + } + + public void UpdateIfDirty(Player player) + { + if (dirty) + { + dirty = false; + if (handle.IsValid) + Timing.KillCoroutines(handle); + stop_watch.Restart(); + handle = Timing.RunCoroutine(_Update(player)); + } + } + + + public IEnumerator _Update(Player player) + { + float delta = 1.0f; + while (delta > 0.0f) + { + delta = Update(player, (float)stop_watch.Elapsed.TotalSeconds); + yield return Timing.WaitForSeconds(delta); + } + yield break; + } + } + + static Dictionary broadcast_info = new Dictionary(); + + public static void SetEvenLineSizes(Player player, int line_count) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].SetEvenLineSizes(line_count); + } + + public static void SetCustomLineSizes(Player player, IEnumerable sizes) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].SetCustomLineSizes(sizes); + } + + public static void RegisterPlayer(Player player) + { + if (!broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info.Add(player.PlayerId, new BroadcastInfo()); + } + + public static void UnregisterPlayer(Player player) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info.Remove(player.PlayerId); + } + + public static void Reset() + { + broadcast_info.Clear(); + } + + public static void BroadcastLine(Player player, int line, float duration, BroadcastPriority priority, string msg) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].BroadcastLine(line, duration, priority, msg); + } + + public static void BroadcastLine(int line, float duration, BroadcastPriority priority, string msg) + { + foreach (Player player in Player.GetPlayers()) + if (player.Role != PlayerRoles.RoleTypeId.None) + BroadcastLine(player, line, duration, priority, msg); + } + + public static void BroadcastLines(Player player, int line, float duration, BroadcastPriority priority, List msgs) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + { + foreach (string msg in msgs) + { + broadcast_info[player.PlayerId].BroadcastLine(line, duration, priority, msg); + line++; + } + } + } + + public static void BroadcastLines(int line, float duration, BroadcastPriority priority, List msgs) + { + foreach (Player player in Player.GetPlayers()) + if (player.Role != PlayerRoles.RoleTypeId.None) + BroadcastLines(player, line, duration, priority, msgs); + } + + public static void ClearLines(Player player, BroadcastPriority priority) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].ClearLines(priority); + } + + public static void ClearLines(BroadcastPriority priority) + { + foreach (Player player in Player.GetPlayers()) + if (player.Role != PlayerRoles.RoleTypeId.None) + ClearLines(player, priority); + } + + public static void ClearLine(Player player, int line, BroadcastPriority priority) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].ClearLine(line, priority); + } + + public static void ClearLine(int line, BroadcastPriority priority) + { + foreach (Player player in Player.GetPlayers()) + if (player.Role != PlayerRoles.RoleTypeId.None) + ClearLine(player, line, priority); + } + + public static void UpdateIfDirty(Player player) + { + if (broadcast_info.ContainsKey(player.PlayerId)) + broadcast_info[player.PlayerId].UpdateIfDirty(player); + } + + public static void UpdateAllDirty() + { + foreach (Player player in Player.GetPlayers()) + if (player.Role != PlayerRoles.RoleTypeId.None) + UpdateIfDirty(player); + } + + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Features/Menu.cs b/AutoEvent/InventoryMenu/API/Features/Menu.cs new file mode 100644 index 00000000..197f67e7 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Features/Menu.cs @@ -0,0 +1,214 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: Menu.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 2:17 PM +// Created Date: 10/27/2023 2:17 PM +// ----------------------------------------- + +using System.Collections.ObjectModel; +using HarmonyLib; + using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventorySystem; +using InventorySystem.Items; +using InventorySystem.Items.Pickups; +using PluginAPI.Core; +using PluginAPI.Core.Items; + +namespace InventoryMenu.API.Features; + +public sealed class Menu +{ + private static int Index { get; set; } = 0; + public static Menu? GetMenu(int id) + { + return MenuManager.Menus.FirstOrDefault(x => x.Id == id); + } + public Menu(string description, bool canPickupItems = false, Action? onGetMenuItems = null, Dictionary? items = null) + { + this.Id = Index; + Index++; + this.CanPlayersPickupItems = canPickupItems; + this.Description = description; + this._activePlayers = new List(); + this._items = items ?? new Dictionary(); + if (onGetMenuItems is not null) + { + GetMenuItems += onGetMenuItems; + } + MenuManager.RegisterMenu(this); + } + /// + /// The of the menu. Unique for every menu. + /// + public int Id { get; private set; } + + /// + /// A description of the menu. + /// + public string Description { get; set; } + + /// + /// Gets or Sets whether a can pickup an item. + /// + /// True if the player can pickup an item. False if a player cannot pickup items. + public bool CanPlayersPickupItems { get; set; } = false; + + public event Action GetMenuItems; + public void OnGetMenuItems(GetMenuItemsForPlayerArgs ev) => GetMenuItems?.Invoke(ev); + + /// + /// An internal dictionary of menu items corresponding to their position. + /// + internal Dictionary _items { get; set; } + + /// + /// A read-only dictionary of menu items and their corresponding positions. + /// + public ReadOnlyDictionary Items => new(_items); + + /// + /// Adds a to the menu. + /// + /// The to add. + /// True if the item can be added, False if the item cannot be added. + public bool AddItem(MenuItem item) + { + if (_items.Count >= 8) + return false; + + byte position = (item.CachedPosition == 255) ? (byte)0 : item.CachedPosition; + + // Something already exists there. + if (_items.ContainsKey(position)) + { + for (byte i = 0; i < 8; i++) + { + if (_items.ContainsKey(i)) + continue; + position = i; + break; + } + } + + _items.Add(position, item); + + item.CachedPosition = 255; + ushort serial = ItemSerialGenerator.GenerateNext(); + if(InventoryItemLoader.AvailableItems.TryGetValue(item.Item, out var value) && value is not null) + { + this._itemBases.Add(serial, value); + item.Serial = serial; + return true; + } + // ItemBase itemBase = ply.ReferenceHub.inventory.CreateItemInstance(new ItemIdentifier(item.Info.ItemId, serial), ply.ReferenceHub.inventory.isLocalPlayer); + return true; + } + + public bool RemoveItem(MenuItem item) + { + if (!_items.ContainsValue(item)) + { + return false; + // dont try to remove it + } + + if (_itemBases.ContainsKey(item.Serial)) + _itemBases.Remove(item.Serial); + byte key = _items.FirstOrDefault(x => x.Value == item).Key; + _items.Remove(key); + item.AssignParentMenu(null); + return true; + } + + public bool ChangeItemIndex(byte oldPosition, byte newPosition) + { + // Old position doesnt exist. + if (!_items.ContainsKey(oldPosition)) + return false; + + // Not moving anything. + if (oldPosition == newPosition) + return true; + + // Something already exists there. + if (_items.ContainsKey(newPosition)) + return false; + + // Add the new index. + _items.Add(newPosition, _items[oldPosition]); + // Remove the old index. + _items.Remove(oldPosition); + return true; + } + + private List _activePlayers { get; set; } + + /// + /// The instances of players viewing this menu. + /// + public IReadOnlyList PlayerInventoryCaches => _activePlayers.AsReadOnly(); + + /// + /// Checks if a player is being shown the menu. + /// + /// The name of the player. + /// + public bool CanPlayerSee(Player ply) + { + return _activePlayers.Contains(ply); + } + + /// + /// Shows a menu to a player. + /// + /// The to show the menu to. + public void ShowToPlayer(Player ply) + { + if (_activePlayers.Contains(ply)) + return; + ply.HideMenu(); + _activePlayers.Add(ply); + List broadcast = new List(); + if (this.Description != "") + broadcast.Add(this.Description); + for (byte i = 0; i < this._items.Count(); i++) + { + if (this._items[i].Description != "") + broadcast.Add(this._items[i].Description); + } + if (!broadcast.IsEmpty()) + { + if (broadcast.Count >= 7) + BroadcastOverride.SetEvenLineSizes(ply, broadcast.Count() + 1); + else + BroadcastOverride.SetEvenLineSizes(ply, 7); + BroadcastOverride.BroadcastLines(ply, 1, 1500.0f, BroadcastPriority.High, broadcast); + } + + + ply.ReferenceHub.inventory.SendItemsNextFrame = true; + } + + /// + /// Hides the menu for a player. + /// + /// The to hide the menu from. + public void HideForPlayer(Player ply) + { + if (!_activePlayers.Contains(ply)) + return; + + _activePlayers.Remove(ply); + ply.ReferenceHub.inventory.SendItemsNextFrame = true; + + } + + public Dictionary _itemBases { get; set; } = new Dictionary(); + public ReadOnlyDictionary ItemBases => new(_itemBases); +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Features/MenuInfo.cs b/AutoEvent/InventoryMenu/API/Features/MenuInfo.cs new file mode 100644 index 00000000..39678d31 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Features/MenuInfo.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: MenuInfo.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 3:18 PM +// Created Date: 10/27/2023 3:18 PM +// ----------------------------------------- + +namespace InventoryMenu.API.Features; + +/// +/// Contains info about a menu. +/// +public struct MenuInfo +{ + /// + /// The amount of items a menu has. + /// + public int TotalItems; + + /// + /// The amount of lines a menu takes. + /// + public int BroadcastLines; + public MenuInfo(int totalItems, int broadcastLines) + { + this.TotalItems = totalItems; + this.BroadcastLines = broadcastLines; + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Features/MenuItem.cs b/AutoEvent/InventoryMenu/API/Features/MenuItem.cs new file mode 100644 index 00000000..2a0d2973 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Features/MenuItem.cs @@ -0,0 +1,139 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: MenuItem.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 2:09 PM +// Created Date: 10/27/2023 2:09 PM +// ----------------------------------------- + +using InventoryMenu.API.EventArgs; +using PluginAPI.Core; + +namespace InventoryMenu.API.Features; + +public sealed class MenuItem +{ + /// + /// Used to track items. + /// + private static int Index { get; set; } = 0; + + public MenuItem(ItemType item, string description, byte position = 255, Action? onClicked = null, Menu? parent = null) + { + CachedPosition = position; + + Id = Index; + Index++; + + this.Item = item; + this.Description = description; + if (onClicked is not null) + { + Clicked += onClicked; + } + + if (parent is not null) + { + ParentMenu = parent; + } + } + + public int Id { get; private set; } + + /// + /// The item type of the selection. + /// + public ItemType Item { get; private set; } + + /// + /// The serial of the item. + /// + public ushort Serial { get; internal set; } + + /// + /// The description shown to players for the item. + /// + public string Description { get; set; } + + /// + /// The position the item should be in. (Between 0 and 7) + /// + public byte ItemPosition { + get + { + if (ParentMenu == null) + return CachedPosition == 255 ? (byte) 0 : CachedPosition; + return ParentMenu.Items.First(x => x.Value == this).Key; + } + set => this.ChangePosition(value); + } + + internal byte CachedPosition { get; set; } = 255; + + /// + /// Triggered when a player selects this menu item. + /// + public event Action Clicked; + + /// + /// Invokes + /// + /// The parameters to invoke. + internal void OnClicked(MenuItemClickedArgs ev) => Clicked?.Invoke(ev); + + /// + /// The parent for this . Can be false if a parent hasn't been defined. + /// + public Menu? ParentMenu { get; private set; } + + /// + /// Changes the position that this item will appear in, in the inventory. + /// + /// The new position. + /// True if the item can change positions. False if another item is already using the position. + public bool ChangePosition(byte newPosition) + { + if (ParentMenu is null) + { + CachedPosition = ItemPosition; + return false; + } + + return ParentMenu.ChangeItemIndex(ItemPosition, newPosition); + } + + + /// + /// Assigns this item to a parent menu. + /// + /// + /// + internal void AssignParentMenu(Menu? menu) + { + if (menu == null) + { + if (ParentMenu is not null && ParentMenu.Items.Any(x => x.Value == this)) + { + int parentId = ParentMenu.Id; + ParentMenu = null; + Menu.GetMenu(parentId)?.RemoveItem(this); + } + return; + } + if (menu.Items.Any(x => x.Value == this)) + { + return; + } + if (menu.Items.Count > 7) + { + throw new ArgumentException("The parent menu has too many items."); + } + ParentMenu = menu; + ParentMenu.AddItem(this); + } + +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Features/PlayerInventoryCache.cs b/AutoEvent/InventoryMenu/API/Features/PlayerInventoryCache.cs new file mode 100644 index 00000000..8e0d6f11 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Features/PlayerInventoryCache.cs @@ -0,0 +1,102 @@ +/*// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: PlayerInventory.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 3:37 PM +// Created Date: 10/27/2023 3:37 PM +// ----------------------------------------- + +using HarmonyLib; +using InventorySystem.Items; +using PluginAPI.Core; +using PluginAPI.Core.Items; + +namespace InventoryMenu.API.Features; + +public class PlayerInventoryCache +{ + public PlayerInventoryCache(Player player) + { + Player = player; + InventoryIsCleared = false; + Items = new Dictionary(); + } + + /// + /// The player. + /// + public Player Player { get; private set; } + public bool InventoryIsCleared { get; private set; } + + /// + /// The players inventory. + /// + public Dictionary Items { get; private set; } + + /// + /// Stores and clears the inventory of the player. + /// + public void StoreAndClearInventory() + { + if (Player is null) + { + return; + } + + if (Player.ReferenceHub.inventory.UserInventory.Items is null) + { + return; + } + + InventoryIsCleared = true; + // Store Values. + Items = Player.ReferenceHub.inventory.UserInventory.Items; + try + { + Dictionary itemIds = new Dictionary(); + foreach (var item in Player.ReferenceHub.inventory.UserInventory.Items) + { + itemIds.Add(itemIds.Count, item.Key); + } + + for (int i = 0; i < Player.ReferenceHub.inventory.UserInventory.Items.Count; i++) + { + if (!itemIds.ContainsKey(i)) + { + continue; + } + + var item = Player.ReferenceHub.inventory.UserInventory.Items.Remove(itemIds[i]); + } + } + catch (Exception e) + { + Log.Warn($"Could not clear the users inventory. Exception: \n{e}"); + } + } + + /// + /// Restores the player's old inventory. + /// + public void RestoreInventory() + { + /*Player.ReferenceHub.inventory.UserInventory.Items = Items; + Items.Clear(); + InventoryIsCleared = false; + *//* + } + + + /// + /// Method Not Recommended. + /// + public void ForceClearedInventory(bool inventoryIsCleared) + { + InventoryIsCleared = inventoryIsCleared; + } +} +*/ \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/Log.cs b/AutoEvent/InventoryMenu/API/Log.cs new file mode 100644 index 00000000..1c34ef76 --- /dev/null +++ b/AutoEvent/InventoryMenu/API/Log.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: Log.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 4:01 PM +// Created Date: 10/27/2023 4:01 PM +// ----------------------------------------- + +namespace InventoryMenu.API; + +public class Log +{ + /// + /// Invoked on logging. Hook this to receive logs from the api. + /// + public static event Action OnLog; + + /// + /// Used to log information. + /// + /// The message to send. + /// The of the log. + internal static void Message(string message, LogLevel logLevel) + { + OnLog?.Invoke(message, logLevel); + return; + switch (logLevel) + { + case LogLevel.Debug: + PluginAPI.Core.Log.Debug(message, "Inventory Menus"); + break; + case LogLevel.Info: + PluginAPI.Core.Log.Info(message, "Inventory Menus"); + break; + case LogLevel.Warn: + PluginAPI.Core.Log.Warning(message, "Inventory Menus"); + break; + case LogLevel.Error: + PluginAPI.Core.Log.Error(message, "Inventory Menus"); + break; + } + } + + internal static void Debug(string message) => Message(message, LogLevel.Debug); + internal static void Warn (string message) => Message(message, LogLevel.Warn); + internal static void Error(string message) => Message(message, LogLevel.Error); + internal static void Info (string message) => Message(message, LogLevel.Info); + + public enum LogLevel + { + /// + /// Debugging information. Users typically don't need to see this. + /// + Debug, + + /// + /// Non-Critical Errors. + /// + Warn, + + /// + /// Critical Errors. + /// + Error, + + /// + /// General API Information. + /// + Info + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/API/MenuManager.cs b/AutoEvent/InventoryMenu/API/MenuManager.cs new file mode 100644 index 00000000..262be38e --- /dev/null +++ b/AutoEvent/InventoryMenu/API/MenuManager.cs @@ -0,0 +1,80 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: MenuManager.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 3:08 PM +// Created Date: 10/27/2023 3:08 PM +// ----------------------------------------- + +using HarmonyLib; +using InventoryMenu.API.Features; +using PluginAPI.Core.Attributes; + +namespace InventoryMenu.API; + +public sealed class MenuManager +{ + static MenuManager() + { + _menus = new List(); + } + + /// The main instance of Harmony. + internal static Harmony Harmony { get; set; } + + /// + /// Where all registered menus are stored. + /// + public static IReadOnlyList Menus => _menus.AsReadOnly(); + + /// + /// The modifiable collection holding the instances of menus. + /// + private static List _menus { get; set; } + + /// + /// The public singleton instance of the menu manager. + /// + public static MenuManager Singleton { get; private set; } + + /// + /// Initializes the . This is required for the menu system to work. + /// + [PluginEntryPoint("Inventory Menus", "v1.0.1", "Provides Inventory Menus", "Redforce04")] + public static void Init() => new MenuManager(); + + /// + /// Registers a menu. + /// + /// The menu to register. + internal static void RegisterMenu(Menu menu) + { + if(!_menus.Contains(menu)) + _menus.Add(menu); + } + + /// + /// Initializes the menu manager. + /// + public MenuManager() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (Singleton is not null) + return; + + Singleton = this; + CosturaUtility.Initialize(); + InventoryMenu.Internal.Handlers.Init(); + Harmony = new Harmony("me.redforce04.inventorymenus"); + Harmony.PatchAll(); + Log.Debug("Inventory Manager Initialized."); + } + + + + +} diff --git a/AutoEvent/InventoryMenu/FodyWeavers.xml b/AutoEvent/InventoryMenu/FodyWeavers.xml new file mode 100644 index 00000000..0b56460e --- /dev/null +++ b/AutoEvent/InventoryMenu/FodyWeavers.xml @@ -0,0 +1,11 @@ + + + + Newtonsoft.Json + 0Harmony + System.ComponentModel.DataAnnotations + YamlDotNet + + + + \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/Internal/Handlers.cs b/AutoEvent/InventoryMenu/Internal/Handlers.cs new file mode 100644 index 00000000..424034c4 --- /dev/null +++ b/AutoEvent/InventoryMenu/Internal/Handlers.cs @@ -0,0 +1,43 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: Handlers.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 4:22 PM +// Created Date: 10/27/2023 4:22 PM +// ----------------------------------------- + +using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventoryMenu.API.Features; +using PluginAPI.Core; +using PluginAPI.Core.Attributes; +using PluginAPI.Enums; +using PluginAPI.Events; + +namespace InventoryMenu.Internal; + +internal class Handlers +{ + internal static Handlers Singleton { get; private set; } + internal static void Init() => new Handlers(); + internal Handlers() + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (Singleton is not null) + return; + + Singleton = this; + EventManager.RegisterEvents(this); + } + + [PluginEvent(ServerEventType.PlayerSearchPickup)] + internal bool OnPickupItem(PlayerSearchPickupEvent ev) + { + var menu = MenuManager.Menus.FirstOrDefault(x => x.CanPlayerSee(ev.Player)); + return menu?.CanPlayersPickupItems ?? true; + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/Internal/Patches/DropItemPatch.cs b/AutoEvent/InventoryMenu/Internal/Patches/DropItemPatch.cs new file mode 100644 index 00000000..4a8f22dd --- /dev/null +++ b/AutoEvent/InventoryMenu/Internal/Patches/DropItemPatch.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: DropItemPatch.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 11:19 PM +// Created Date: 10/27/2023 11:19 PM +// ----------------------------------------- + +using HarmonyLib; +using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventorySystem; +using PluginAPI.Core; + +namespace InventoryMenu.Internal.Patches; + +[HarmonyPatch(typeof(Inventory), nameof(Inventory.UserCode_CmdDropItem__UInt16__Boolean))] + +internal class DropItemPatch +{ + internal static bool Prefix(Inventory __instance, ushort itemSerial, bool tryThrow) + { + if (tryThrow) + return true; + Player ply = Player.Get(__instance._hub); + var instance = MenuManager.Menus.FirstOrDefault(x => x.CanPlayerSee(ply)); + if (instance is null) + { + return true; + } + + var item = instance.Items.FirstOrDefault(x => x.Value.Serial == itemSerial).Value; + if (item is null) + { + return false; + } + + try + { + item.OnClicked(new MenuItemClickedArgs(ply, item, false)); + } + catch (Exception e) + { + + } + return false; + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/Internal/Patches/InventorySystemPatch.cs b/AutoEvent/InventoryMenu/Internal/Patches/InventorySystemPatch.cs new file mode 100644 index 00000000..2f445df3 --- /dev/null +++ b/AutoEvent/InventoryMenu/Internal/Patches/InventorySystemPatch.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: InventorySystemPatch.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 5:21 PM +// Created Date: 10/27/2023 5:21 PM +// ----------------------------------------- + +using System.Diagnostics; +using System.Text; +using HarmonyLib; +using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventoryMenu.API.Features; +using InventorySystem.Items; +using NorthwoodLib.Pools; +using PluginAPI.Core; +using Log = InventoryMenu.API.Log; + +namespace InventoryMenu.Internal.Patches; + +[HarmonyPatch(typeof(InventorySystem.Inventory), nameof(InventorySystem.Inventory.ServerSendItems))] +internal static class InventorySystemPatch +{ + internal static bool Prefix(InventorySystem.Inventory __instance) + { + if (__instance.isLocalPlayer) + { + return false; + } + + HashSet hashSet = HashSetPool.Shared.Rent(); + Player ply = Player.Get(__instance._hub); + var instance = MenuManager.Menus.FirstOrDefault(x => x.CanPlayerSee(ply)); + GetMenuItemsForPlayerArgs? args = null; + + if (instance is not null) + { + try + { + args = new GetMenuItemsForPlayerArgs(ply, instance); + instance.OnGetMenuItems(args); + } + catch (Exception e) + { + Log.Debug($"An error has occured while getting menu items.\n {e}"); + } + } + var items = (args is not null ? args.Items : __instance.UserInventory.Items); + // Log.Debug($"[{instance is null}], Menus: {MenuManager.Menus.Count}, Total Caches: {MenuManager.Menus.Sum(x => x.PlayerInventoryCaches.Count())}"); + + // Log.Debug($"Item Count: {items.Count}, Inv Count: {__instance.UserInventory.Items.Count} Menu null: {instance is null}, "); + foreach (KeyValuePair item in items.OrderByDescending(x => x.Key)) + { + hashSet.Add(new ItemIdentifier(item.Value.ItemTypeId, item.Key)); + } + + __instance.TargetRefreshItems(hashSet.ToArray()); + HashSetPool.Shared.Return(hashSet); + return false; + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/Internal/Patches/SelectItemPatch.cs b/AutoEvent/InventoryMenu/Internal/Patches/SelectItemPatch.cs new file mode 100644 index 00000000..57f54fd2 --- /dev/null +++ b/AutoEvent/InventoryMenu/Internal/Patches/SelectItemPatch.cs @@ -0,0 +1,49 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: InventoryMenu +// FileName: SelectItemPatch.cs +// Author: Redforce04#4091 +// Revision Date: 10/27/2023 11:08 PM +// Created Date: 10/27/2023 11:08 PM +// ----------------------------------------- + +using HarmonyLib; +using InventoryMenu.API; +using InventoryMenu.API.EventArgs; +using InventorySystem; +using PluginAPI.Core; + +namespace InventoryMenu.Internal.Patches; + +[HarmonyPatch(typeof(Inventory), nameof(Inventory.UserCode_CmdSelectItem__UInt16))] +internal static class SelectItemPatch +{ + internal static bool Prefix(Inventory __instance, ushort itemSerial) + { + Player ply = Player.Get(__instance._hub); + var instance = MenuManager.Menus.FirstOrDefault(x => x.CanPlayerSee(ply)); + if (instance is null) + { + return true; + } + + var item = instance.Items.FirstOrDefault(x => x.Value.Serial == itemSerial).Value; + if (item is null) + { + return false; + } + + try + { + item.OnClicked(new MenuItemClickedArgs(ply, item, true)); + } + catch (Exception e) + { + + } + return false; + } +} \ No newline at end of file diff --git a/AutoEvent/InventoryMenu/InventoryMenu.csproj b/AutoEvent/InventoryMenu/InventoryMenu.csproj new file mode 100644 index 00000000..a7ccf644 --- /dev/null +++ b/AutoEvent/InventoryMenu/InventoryMenu.csproj @@ -0,0 +1,56 @@ + + + + latest + InventoryMenu + InventoryMenu + Copyright RisottoMan and Redforce04 © 2023 + bin\$(Configuration)\ + Release + AnyCPU + false + net48 + enable + enable + true + + + + + + all + runtime; compile; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; compile; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutoEvent/Loader.cs b/AutoEvent/Loader.cs index 2f5ec0f7..71d57f99 100644 --- a/AutoEvent/Loader.cs +++ b/AutoEvent/Loader.cs @@ -15,9 +15,9 @@ public class Loader /// Overrides the Exiled check for the version of the plugin that is exiled exclusive. /// #if EXILED - private const bool IsExiledPlugin = true; + public const bool IsExiledPlugin = true; #else - private const bool IsExiledPlugin = false; + public const bool IsExiledPlugin = false; #endif /// /// If enabled, a debug log is output everytime a plugin is loaded. Not necessary for players. @@ -33,7 +33,7 @@ public class Loader /// Checks to see if exiled is present on this server. /// /// - private static bool isExiledPresent() + internal static bool isExiledPresent() { if (IsExiledPlugin) { diff --git a/AutoEvent/Patches/ShotPatch.cs b/AutoEvent/Patches/ShotPatch.cs new file mode 100644 index 00000000..ae104451 --- /dev/null +++ b/AutoEvent/Patches/ShotPatch.cs @@ -0,0 +1,204 @@ +#if !EXILED +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +using System.Collections.Generic; +using System.Reflection.Emit; +using AutoEvent.Events.EventArgs; +using AutoEvent.Events; +using HarmonyLib; +using InventorySystem.Items.Firearms; +using InventorySystem.Items.Firearms.Modules; +using NorthwoodLib.Pools; +using PluginAPI.Core; +using UnityEngine; +using AutoEvent.Events.Handlers; + +namespace AutoEvent.Patches +{ +#pragma warning disable SA1402 // File may only contain a single type + + using static HarmonyLib.AccessTools; + + + [HarmonyPatch(typeof(SingleBulletHitreg), nameof(SingleBulletHitreg.ServerProcessRaycastHit))] + internal static class Shot + { + /// + /// I DON'T CARE. + /// + /// Fuck Player. + /// Fuck Hit. + /// FuckDestructible. + /// FuckDamage. + /// FuckReturn. + internal static bool ProcessShot(ReferenceHub player, RaycastHit hit, IDestructible destructible, ref float damage) + { + ShotEventArgs shotEvent = new(Player.Get(player), hit, destructible, damage); + + global::AutoEvent.Events.Handlers.Players.OnShot(shotEvent); + + if (shotEvent.CanHurt) + damage = shotEvent.Damage; + + return shotEvent.CanHurt; + } + + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Shared.Rent(instructions); + + Label returnLabel = generator.DefineLabel(); + Label jump = generator.DefineLabel(); + + LocalBuilder ev = generator.DeclareLocal(typeof(ShotEventArgs)); + + int offset = 2; + int index = newInstructions.FindLastIndex( + instruction => instruction.Calls(Method(typeof(FirearmBaseStats), nameof(FirearmBaseStats.DamageAtDistance)))) + offset; + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + // this.Hub + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.Hub))), + + // hit + new(OpCodes.Ldarg_2), + + // destructible + new(OpCodes.Ldloc_0), + + // damage + new(OpCodes.Ldloca_S, 1), + + new(OpCodes.Call, Method(typeof(Shot), nameof(ProcessShot), new[] { typeof(ReferenceHub), typeof(RaycastHit), typeof(IDestructible), typeof(float).MakeByRefType(), })), + + // if (!ev.CanHurt) + // return; + new(OpCodes.Brfalse_S, returnLabel), + }); + + offset = -3; + index = newInstructions.FindLastIndex( + instruction => instruction.Calls(Method(typeof(StandardHitregBase), nameof(StandardHitregBase.PlaceBulletholeDecal)))) + offset; + + // replace the original goto label + newInstructions.FindAll(instruction => instruction.opcode == OpCodes.Brfalse).ForEach(instruction => instruction.operand = jump); + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + new CodeInstruction(OpCodes.Nop).WithLabels(jump), + + // this.Hub + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.Hub))), + + // hit + new(OpCodes.Ldarg_2), + + // destructible + new(OpCodes.Ldnull), + + // damage + new(OpCodes.Ldc_R4, 0f), + new(OpCodes.Stloc_S, 1), + new(OpCodes.Ldloca_S, 1), + + // Shot.ProcessShot + new(OpCodes.Call, Method(typeof(Shot), nameof(ProcessShot), new[] { typeof(ReferenceHub), typeof(RaycastHit), typeof(IDestructible), typeof(float).MakeByRefType(), })), + new(OpCodes.Pop), + }); + + newInstructions[newInstructions.Count - 1].WithLabels(returnLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Shared.Return(newInstructions); + } + } + + [HarmonyPatch(typeof(BuckshotHitreg), nameof(BuckshotHitreg.ShootPellet))] + internal static class Shot2 + { + private static IEnumerable Transpiller(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Shared.Rent(instructions); + + Label returnLabel = generator.DefineLabel(); + + int offset = -3; + int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(StandardHitregBase), nameof(StandardHitregBase.PlaceBulletholeDecal)))) + offset; + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + // this.Hub + new CodeInstruction(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(BuckshotHitreg), nameof(BuckshotHitreg.Hub))), + + // hit + new(OpCodes.Ldloc_2), + + // destructible + new(OpCodes.Ldloc_3), + + // damage + new(OpCodes.Ldc_R4, 0f), + new(OpCodes.Stloc_S, 4), + new(OpCodes.Ldloca_S, 4), + + new(OpCodes.Call, Method(typeof(Shot), nameof(Shot.ProcessShot), new[] { typeof(ReferenceHub), typeof(RaycastHit), typeof(IDestructible), typeof(float).MakeByRefType(), })), + + // if (!ev.CanHurt) + // return; + new(OpCodes.Brfalse_S, returnLabel), + }); + + offset = 0; + index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldsfld) + offset; + + newInstructions.InsertRange( + index, + new[] + { + // this.Hub + new CodeInstruction(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(BuckshotHitreg), nameof(BuckshotHitreg.Hub))), + + // hit + new(OpCodes.Ldloc_2), + + // destructible + new(OpCodes.Ldloc_3), + + // damage + new(OpCodes.Ldloca_S, 4), + + new(OpCodes.Call, Method(typeof(Shot), nameof(Shot.ProcessShot), new[] { typeof(ReferenceHub), typeof(RaycastHit), typeof(IDestructible), typeof(float).MakeByRefType(), })), + + // if (!ev.CanHurt) + // return; + new(OpCodes.Brfalse_S, returnLabel), + }); + + newInstructions[newInstructions.Count - 1].WithLabels(returnLabel); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Shared.Return(newInstructions); + } + } +} +#endif \ No newline at end of file diff --git a/AutoEvent/Plugin.cs b/AutoEvent/Plugin.cs index 63192b17..7f3c9b77 100644 --- a/AutoEvent/Plugin.cs +++ b/AutoEvent/Plugin.cs @@ -1,6 +1,7 @@ using System; using System.IO; using AutoEvent.Commands; +using AutoEvent.Events.EventArgs; using AutoEvent.Interfaces; using HarmonyLib; using PluginAPI.Core.Attributes; @@ -14,7 +15,9 @@ using Powerups; using Event = AutoEvent.Interfaces.Event; using Log = PluginAPI.Core.Log; +using Map = PluginAPI.Core.Map; using Paths = PluginAPI.Helpers.Paths; +using Player = PluginAPI.Core.Player; using Server = PluginAPI.Core.Server; #if EXILED using Exiled.API.Features; @@ -25,7 +28,7 @@ namespace AutoEvent #if EXILED public class AutoEvent : Plugin { - public override System.Version Version => new System.Version(9, 2, 0); + public override System.Version Version => System.Version.Parse(DebugLogger.Version); public override string Name => "AutoEvent"; public override string Author => "Created by KoT0XleB, extended by swd and sky, Co-Maintained by Redforce04"; public static bool IsPlayedGames; @@ -55,7 +58,7 @@ public class AutoEvent public override void OnEnabled() #else [PluginPriority(LoadPriority.Low)] - [PluginEntryPoint("AutoEvent", "9.2.0", "An event manager plugin that allows you to run mini-games.", + [PluginEntryPoint("AutoEvent", DebugLogger.Version, "An event manager plugin that allows you to run mini-games.", "KoT0XleB and Redforce04")] void OnEnabled() #endif @@ -88,6 +91,15 @@ private void _startup() Singleton = this; MER.Lite.API.Initialize(AutoEvent.Singleton.Config.SchematicsDirectoryPath, Config.Debug); Powerups.API.Initialize(); + #if EXILED + Exiled.Events.Handlers.Player.Shot += (Exiled.Events.EventArgs.Player.ShotEventArgs ev) => + { + var args = new ShotEventArgs(Player.Get(ev.Player.ReferenceHub), ev.RaycastHit, ev.Hitbox, ev.Damage); + global::AutoEvent.Events.Handlers.Players.OnShot(args); + ev.Damage = args.Damage; + ev.CanHurt = args.CanHurt; + }; + #endif if (Config.IgnoredRoles.Contains(Config.LobbyRole)) { @@ -196,5 +208,35 @@ public override void OnDisabled() HarmonyPatch.UnpatchAll(); Singleton = null; } + + public void OnEventFinished() + { + if (Config.RestartAfterRoundFinish && !DebugLogger.NoRestartEnabled) + { + foreach (Player ply in Player.GetPlayers()) + { + if (ply.CheckPermission("ev.norestart", out bool isConsole)) + { + ply.ClearBroadcasts(); + ply.SendBroadcast($"The server is going to restart in 10 seconds. Use the `Ev NoRestart` command to prevent this.", 10); + } + } + Timing.CallDelayed(7f, () => + { + if (Config.RestartAfterRoundFinish && !DebugLogger.NoRestartEnabled) + { + Map.ClearBroadcasts(); + Map.Broadcast(5, Config.ServerRestartMessage); + } + }); + Timing.CallDelayed(10f, () => + { + if (Config.RestartAfterRoundFinish && !DebugLogger.NoRestartEnabled) + { + Server.Restart(); + } + }); + } + } } } diff --git a/AutoEvent/PowerupApi/PowerupApi.csproj b/AutoEvent/PowerupApi/PowerupApi.csproj index 47c05f17..91a14212 100644 --- a/AutoEvent/PowerupApi/PowerupApi.csproj +++ b/AutoEvent/PowerupApi/PowerupApi.csproj @@ -43,11 +43,11 @@ - - - + + + - + diff --git a/AutoEvent/ReleaseInfo.cs b/AutoEvent/ReleaseInfo.cs new file mode 100644 index 00000000..bdd04d02 --- /dev/null +++ b/AutoEvent/ReleaseInfo.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Redforce04. All rights reserved. +// +// ----------------------------------------- +// Solution: AutoEvent +// Project: AutoEvent +// FileName: ReleaseInfo.cs +// Author: Redforce04#4091 +// Revision Date: 10/22/2023 9:49 PM +// Created Date: 10/22/2023 9:49 PM +// ----------------------------------------- + +using System; + +namespace AutoEvent; + +public struct ReleaseInfo +{ + public ReleaseInfo(string version, Version semanticVersion, string name, string changelog, DateTime releaseDate) + { + Version = version; + SemanticVersion = semanticVersion; + Name = name; + ChangeLog = changelog; + ReleaseDate = releaseDate; + } + public string Name { get; } + public string Version { get; } + public Version SemanticVersion { get; } + public string ChangeLog { get; } + public DateTime ReleaseDate { get; set; } +} \ No newline at end of file diff --git a/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xml b/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xml new file mode 100644 index 00000000..7b756df5 --- /dev/null +++ b/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xml @@ -0,0 +1,7 @@ + + + + Exiled.API + + + \ No newline at end of file diff --git a/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xsd b/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xsd new file mode 100644 index 00000000..05e92c11 --- /dev/null +++ b/AutoEvent/ReplaceTextWithVariables/FodyWeavers.xsd @@ -0,0 +1,141 @@ + + + + + + + + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with line breaks. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with line breaks. + + + + + The order of preloaded assemblies, delimited with line breaks. + + + + + + This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. + + + + + Controls if .pdbs for reference assemblies are also embedded. + + + + + Controls if runtime assemblies are also embedded. + + + + + Controls whether the runtime assemblies are embedded with their full path or only with their assembly name. + + + + + Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. + + + + + As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. + + + + + Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. + + + + + Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. + + + + + A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with | + + + + + A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |. + + + + + A list of unmanaged 32 bit assembly names to include, delimited with |. + + + + + A list of unmanaged 64 bit assembly names to include, delimited with |. + + + + + The order of preloaded assemblies, delimited with |. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/AutoEvent/ReplaceTextWithVariables/Program.cs b/AutoEvent/ReplaceTextWithVariables/Program.cs new file mode 100644 index 00000000..92262c5b --- /dev/null +++ b/AutoEvent/ReplaceTextWithVariables/Program.cs @@ -0,0 +1,436 @@ +// See https://aka.ms/new-console-template for more information +// dotnet publish -r win-x64 -c Release + +using System.Collections; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using Exiled.API.Features; +using Exiled.API.Interfaces; +using Microsoft.VisualBasic.FileIO; +using Newtonsoft.Json; +using PluginAPI.Core.Attributes; + +public static class Program +{ + public static void Main(string[] args) + { + CosturaUtility.Initialize(); + bool ReplaceEnvironmentalVariables = true; + Dictionary replacementTerms = new Dictionary(); + string fileLoc = ""; + List EnvironmentalVariables = new List(); + + if (args.Length == 0) + { + Console.Error.WriteLine("No file specified. Could not replace variables."); + return; + } + + List nextArguments = new List(); + for (int i = 0; i < args.Length; i++) + { + string argument = args[i]; + //Console.WriteLine($"Argument: {argument}"); + nextArguments.Clear(); + if (argument.StartsWith('-')) + { + switch (argument) + { + case "-d" or "--datetime": + if (args.TryProcessNextArguments(i, 1, out nextArguments)) + { + i += 1; + replacementTerms.Add(nextArguments[0], DateTime.UtcNow.ToString("s")); + } + continue; + case "-v" or "--var": + //Console.WriteLine($"var"); + if (args.TryProcessNextArguments(i, 2, out nextArguments)) + { + replacementTerms.Add(nextArguments[0], nextArguments[1]); + i += 2; + Console.WriteLine($"var: {nextArguments[0]}, {nextArguments[1]}"); + } + continue; + + case "-ne" or "--no-environmental": + //Console.WriteLine($"no env"); + ReplaceEnvironmentalVariables = false; + continue; + + case "-e" or "--environmental": + //Console.WriteLine($"env"); + if (args.TryProcessNextArguments(i, 1, out nextArguments)) + { + EnvironmentalVariables.Add(nextArguments[0]); + i += 1; + //Console.WriteLine($"env: {nextArguments[0]}"); + } + continue; + + case "-cmd" or "--cmd-variable": + if (args.TryProcessNextArguments(i, 2, out nextArguments)) + { + i += 2; + string procName = nextArguments[0].Split(' ')[0]; + string procArgs = nextArguments[0].Replace($"{procName} ", ""); + //procArgs = ""; + //Console.WriteLine($"starting process {procName}"); + Process proc = new Process() { StartInfo = new ProcessStartInfo(procName,procArgs) + { + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }}; + proc.Start(); + string output = ""; + while (!proc.StandardOutput.EndOfStream) + { + output += proc.StandardOutput.ReadLine(); + } + proc.WaitForExit(); + //Console.WriteLine($"{output}"); + replacementTerms.Add($"{nextArguments[1]}", output); + } + continue; + case "-bd" or "--build-dependencies": + if (args.TryProcessNextArguments(i, 2, out nextArguments)) + { + i += 2; + string folderLoc = Path.GetFullPath(nextArguments[0]); + if (!Directory.Exists(folderLoc)) + { + Console.Error.WriteLine($"Could not find folder \"{folderLoc}\"."); + continue; + } + + string output = ""; + List buildDependencies = new List(); + foreach (string file in Directory.GetFiles(folderLoc, "*.dll")) + { + try + { + Assembly assembly = null!; + assembly = Assembly.Load(File.ReadAllBytes(file)); + + var version = assembly.GetCustomAttribute()?.InformationalVersion ?? ""; + AssemblyInfo dp = new AssemblyInfo() + { + Hash = assembly.ManifestModule.ModuleVersionId.ToString(), + Name = assembly.GetName().ToString(), + Exiled = false, + Version = version, + }; + if (CreatePlugin(assembly) is { } plif) + { + dp.Plugins.Add(plif); + } + + var plugins = GetPluginInfo(assembly); + if (plugins.Count > 0) + { + dp.Plugins.AddRange(plugins); + } + buildDependencies.Add(dp); + Console.WriteLine($"Loaded Assembly {dp.Name}"); + } + catch (Exception e) + { + Console.Error.WriteLine($"Could not load assembly for file \"{file}\". Exception: \"{e.Message}\"."); + try + { + var info = dnlib.DotNet.AssemblyDef.Load(file); + AssemblyInfo assemblyInfo = new AssemblyInfo() + { + Name = info.Name, + Version = info.Version.ToString(), + Hash = info.ManifestModule.Mvid.HasValue ? info.ManifestModule.Mvid.Value.ToString() : "", + }; + foreach (var x in info.CustomAttributes) + { + if (x is null) + continue; + + if (x.TypeFullName.ToLower().Contains(nameof(PluginEntryPoint).ToLower())) + { + + Console.WriteLine($""); + } + } + buildDependencies.Add(assemblyInfo); + Console.Error.WriteLine($"Could not load full assembly for {assemblyInfo.Name}. Loading Mini-Info instead."); + } + catch { } + } + } + + output = JsonConvert.SerializeObject(buildDependencies).Replace("\"","\\\""); + replacementTerms.Add($"{nextArguments[1]}", output); + } + continue; + default: + Console.Error.WriteLine($"Unknown variable \"{argument}\""); + continue; + + } + } + else if (File.Exists(args[i])) + { + fileLoc = args[i]; + continue; + } + else + { + Console.Error.WriteLine($"Unknown Argument \"{argument}\""); + return; + } + } + + if (fileLoc == "") + { + Console.Error.WriteLine($"File location must be specified."); + return; + } + Dictionary varsToReplace = new Dictionary(); + + if (ReplaceEnvironmentalVariables) + { + foreach (DictionaryEntry envVar in Environment.GetEnvironmentVariables()) + { + //Console.WriteLine($"{(string)envVar.Key}, {(string)envVar.Value!}"); + varsToReplace.Add((string)envVar.Key,(string)envVar.Value!); + } + } + + string text = File.ReadAllText(fileLoc); + + foreach (var var in replacementTerms) + { + if (text.Contains(var.Key)) + varsToReplace.Add(var.Key, var.Value); + } + + foreach (var x in varsToReplace) + { + text = text.Replace(x.Key, x.Value); + } + + //Console.WriteLine($"Replacing {varsToReplace.Count + replacementTerms.Count} variables"); + File.WriteAllText(fileLoc, text); + Console.Write(text); + } + + private static bool TryProcessNextArguments(this string[] arguments, int currentTerm, int amountToSearch, out List nextArguments) + { + nextArguments = new List(); + try + { + if (arguments.Length < currentTerm + amountToSearch) + { + Console.Error.WriteLine($"Incorrect argument {arguments[currentTerm]}. Proper Usage: \n{ProperUsage(arguments[currentTerm])}"); + return false; + } + for (int i = currentTerm + 1; i <= currentTerm + amountToSearch; i++) + { + //Console.WriteLine($"{arguments[i]}"); + nextArguments.Add(arguments[i]); + } + return true; + } + catch (Exception e) + { + Console.Error.WriteLine($"Could not process next arguments for var {arguments[currentTerm]}. Error: {e}"); + return false; + } + } + + private static string ProperUsage(string var) + { + switch (var) + { + case "-v" or "--var": + return "(--var / -v) \"string to replace\" \"replacement value\" - replaces a string with a value"; + + case "-ne" or "--no-environmental": + return "(--no-environemental / -ne) - prevents environmental variables from being swapped. (Use -e to add specific variables)"; + + case "-e" or "--environmental": + return "(--environmental / -e) \"environmental variable name\" - replaces an environmental variable."; + case "-cmd" or "--cmd-variable": + return "(--cmd-variable / -cmd) \"command to execute\" \"variable name\" - replaces an variable with the output of a command."; + + } + + return $"Could not find variable {var}"; + } + + private static List GetPluginInfo(Assembly assembly) + { + + List plugins = new List(); + try + { + if (!Attribute.IsDefined(assembly, typeof(PluginEntryPoint))) + { + return plugins; + } + foreach (var type in assembly.GetTypes()) + { + foreach (var method in type.GetMethods()) + { + var entrypoint = method.GetCustomAttribute(); + if (entrypoint is null) + { + continue; + } + plugins.Add(new PluginInfo() + { + Authors = entrypoint.Author, + Name = entrypoint.Name, + ExiledPlugin = false, + Version = entrypoint.Version, + Descriptions = entrypoint.Description, + }); + } + } + } + catch (Exception e) + { } + + return plugins; + } + /// + /// Create a plugin instance. + /// + /// The plugin assembly. + /// Returns the created plugin instance or . + private static PluginInfo? CreatePlugin(Assembly assembly) + { + try + { + foreach (Type type in assembly.GetTypes()) + { + if (type.IsAbstract || type.IsInterface) + { + continue; + } + + if (!IsDerivedFromPlugin(type)) + { + continue; + } + + + IPlugin plugin = null; + + ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); + if (constructor is not null) + { + + plugin = constructor.Invoke(null) as IPlugin; + } + else + { + + object value = Array.Find(type.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public), property => property.PropertyType == type)?.GetValue(null); + + if (value is not null) + plugin = value as IPlugin; + } + + if (plugin is null) + { + + continue; + } + + + + return new PluginInfo() + { + ExiledPlugin = true, + Authors = plugin.Author, + Name = plugin.Name, + Version = plugin.Version.ToString(), + }; + } + } + catch (ReflectionTypeLoadException reflectionTypeLoadException) + { + //Log.Error($"Error while initializing plugin {assembly.GetName().Name} (at {assembly.Location})! {reflectionTypeLoadException}"); + + foreach (Exception loaderException in reflectionTypeLoadException.LoaderExceptions) + { + //Log.Error(loaderException); + } + } + catch (Exception exception) + { + //Log.Error($"Error while initializing plugin {assembly.GetName().Name} (at {assembly.Location})! {exception}"); + } + + return null; + } + + /// + /// Indicates that the passed type is derived from the plugin type. + /// + /// Type. + /// if passed type is derived from or , otherwise . + private static bool IsDerivedFromPlugin(Type type) + { + while (type is not null) + { + type = type.BaseType; + + if (type is { IsGenericType: true }) + { + Type genericTypeDef = type.GetGenericTypeDefinition(); + + if (genericTypeDef == typeof(Plugin<>) || genericTypeDef == typeof(Plugin<,>)) + return true; + } + } + + return false; + } + + internal struct AssemblyInfo + { + public AssemblyInfo() + { + Plugins = new List(); + Exiled = false; + Dependency = false; + Name = ""; + Hash = ""; + Version = ""; + } + public bool Exiled { get; set; } + public bool Dependency { get; set; } + public string Name { get; set; } + public string Hash { get; set; } + public string Version { get; set; } + public List Plugins { get; set; } + } + + internal struct PluginInfo + { + public PluginInfo() + { + ExiledPlugin = false; + Name = ""; + Version = ""; + Authors = ""; + Descriptions = ""; + } + public bool ExiledPlugin { get; set; } + public string Name { get; set; } + public string Version { get; set; } + public string Authors { get; set; } + public string Descriptions { get; set; } + } +} \ No newline at end of file diff --git a/AutoEvent/ReplaceTextWithVariables/ReplaceTextWithVariables.csproj b/AutoEvent/ReplaceTextWithVariables/ReplaceTextWithVariables.csproj new file mode 100644 index 00000000..b183d1dd --- /dev/null +++ b/AutoEvent/ReplaceTextWithVariables/ReplaceTextWithVariables.csproj @@ -0,0 +1,30 @@ + + + + Exe + net7.0 + enable + enable + + + + true + true + + + + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive; compile + + + + + + + + diff --git a/AutoEvent/SchematicApi/SchematicApi.csproj b/AutoEvent/SchematicApi/SchematicApi.csproj index 1fe205bc..2cc45587 100644 --- a/AutoEvent/SchematicApi/SchematicApi.csproj +++ b/AutoEvent/SchematicApi/SchematicApi.csproj @@ -25,7 +25,6 @@ true - bin\Release\SchematicApi.xml @@ -44,11 +43,11 @@ - - - + + + - + diff --git a/AutoEvent/Translation.cs b/AutoEvent/Translation.cs index 3266848d..fd65f80d 100644 --- a/AutoEvent/Translation.cs +++ b/AutoEvent/Translation.cs @@ -2,6 +2,8 @@ using System.ComponentModel; using AutoEvent.Games.Battle; using AutoEvent.Games.Boss; +using AutoEvent.Games.GhostBusters.Configs; +using AutoEvent.Games.Spleef.Configs; #if EXILED using Exiled.API.Interfaces; #endif @@ -49,6 +51,9 @@ public class Translation [Description("Puzzle Game Mode")] public PuzzleTranslate PuzzleTranslate { get; set; } = new PuzzleTranslate(); + [Description("Spleef Game Mode")] + public SpleefTranslation SpleefTranslate { get; set; } = new SpleefTranslation(); + [Description("Zombie Survival Game Mode (Zombie 2)")] public SurvivalTranslate SurvivalTranslate { get; set; } = new SurvivalTranslate(); @@ -75,5 +80,8 @@ public class Translation [Description("Boss Battle Game Mode")] public BossTranslate BossTranslate { get; set; } = new BossTranslate(); + + [Description("Ghost Busters Game Mode")] + public GhostBustersTranslate GhostBustersTranslate { get; set; } = new GhostBustersTranslate(); } }