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
#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();
}
}