Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Interfaces/ISnakeEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// -----------------------------------------------------------------------
// <copyright file="ISnakeEvent.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Interfaces
{
using Exiled.API.Features.Items;
using InventorySystem.Items.Keycards.Snake;

/// <summary>
/// Event args used for all <see cref="Handlers.Snake" /> related events.
/// </summary>
public interface ISnakeEvent : IPlayerEvent
{
/// <summary>
/// Gets the Snake game controller.
/// </summary>
public SnakeEngine Engine { get; }

/// <summary>
/// Gets the keycard that triggered this event.
/// </summary>
public Keycard Keycard { get; }
}
}
49 changes: 49 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Snake/GainedScoreEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// -----------------------------------------------------------------------
// <copyright file="GainedScoreEventArgs.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Snake
{
using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Keycards.Snake;

/// <summary>
/// Contains all information after a player gains score in the Snake minigame.
/// </summary>
public class GainedScoreEventArgs : ISnakeEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="GainedScoreEventArgs" /> class.
/// </summary>
/// <param name="engine">The <see cref="SnakeEngine"/> instance.</param>
/// <param name="player">The <see cref="API.Features.Player"/> who triggered this event.</param>
/// <param name="keycard">The <see cref="Keycard"/> triggering this event.</param>
public GainedScoreEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard)
{
Engine = engine;
Player = player;
Score = engine.Score;
Keycard = keycard;
}

/// <inheritdoc />
public SnakeEngine Engine { get; }

/// <summary>
/// Gets the person playing the game.
/// </summary>
public API.Features.Player Player { get; }

/// <inheritdoc />
public Keycard Keycard { get; }

/// <summary>
/// Gets the newly obtained score.
/// </summary>
public int Score { get; }
}
}
55 changes: 55 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Snake/GameOverEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// -----------------------------------------------------------------------
// <copyright file="GameOverEventArgs.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Snake
{
using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Keycards.Snake;

/// <summary>
/// Contains all information after a player loses at Snake.
/// </summary>
public class GameOverEventArgs : ISnakeEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="GameOverEventArgs" /> class.
/// </summary>
/// <param name="engine">The <see cref="SnakeEngine"/> instance.</param>
/// <param name="player">The <see cref="API.Features.Player"/> who triggered this event.</param>
/// <param name="keycard">The <see cref="Keycard"/> triggering this event.</param>
public GameOverEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard)
{
Engine = engine;
Player = player;
FinalScore = engine.Score;
Length = engine.CurLength;
Keycard = keycard;
}

/// <inheritdoc />
public SnakeEngine Engine { get; }

/// <summary>
/// Gets the person playing the game.
/// </summary>
public API.Features.Player Player { get; }

/// <inheritdoc />
public Keycard Keycard { get; }

/// <summary>
/// Gets the final score.
/// </summary>
public int FinalScore { get; }

/// <summary>
/// Gets the final length of the snake.
/// </summary>
public int Length { get; }
}
}
43 changes: 43 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Snake/NewGameEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// -----------------------------------------------------------------------
// <copyright file="NewGameEventArgs.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Snake
{
using Exiled.API.Features.Items;
using Interfaces;
using InventorySystem.Items.Keycards.Snake;

/// <summary>
/// Contains all information when a player starts a new snake game.
/// </summary>
public class NewGameEventArgs : ISnakeEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="NewGameEventArgs" /> class.
/// </summary>
/// <param name="engine">The <see cref="SnakeEngine"/> instance.</param>
/// <param name="player">The <see cref="API.Features.Player"/> who triggered this event.</param>
/// <param name="keycard">The <see cref="Keycard"/> triggering this event.</param>
public NewGameEventArgs(SnakeEngine engine, API.Features.Player player, Keycard keycard)
{
Engine = engine;
Player = player;
Keycard = keycard;
}

/// <inheritdoc />
public SnakeEngine Engine { get; }

/// <summary>
/// Gets the person playing the game.
/// </summary>
public API.Features.Player Player { get; }

/// <inheritdoc />
public Keycard Keycard { get; }
}
}
1 change: 1 addition & 0 deletions EXILED/Exiled.Events/Exiled.Events.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<Reference Include="UnityEngine.CoreModule" HintPath="$(EXILED_REFERENCES)\UnityEngine.CoreModule.dll" Private="false" />
<Reference Include="UnityEngine.PhysicsModule" HintPath="$(EXILED_REFERENCES)\UnityEngine.PhysicsModule.dll" Private="false" />
<Reference Include="YamlDotNet" HintPath="$(EXILED_REFERENCES)\YamlDotNet.dll" Private="false" />
<Reference Include="Snake" HintPath="$(EXILED_REFERENCES)\Snake.dll" Private="false" />
</ItemGroup>

<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
Expand Down
62 changes: 62 additions & 0 deletions EXILED/Exiled.Events/Handlers/Snake.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// -----------------------------------------------------------------------
// <copyright file="Snake.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.Handlers
{
#pragma warning disable SA1623 // Property summary documentation should match accessors

using Exiled.Events.EventArgs.Snake;
using Features;

/// <summary>
/// Handles Snake related events.
/// </summary>
public class Snake
{
/// <summary>
/// Invoked when gaining score in Snake.
/// </summary>
public static Event<GainedScoreEventArgs> GainedScore { get; set; } = new();

/// <summary>
/// Invoked when a player loses in Snake.
/// </summary>
public static Event<GameOverEventArgs> GameOver { get; set; } = new();

/// <summary>
/// Invoked when a player starts a new game.
/// </summary>
public static Event<NewGameEventArgs> NewGame { get; set; } = new();

/// <summary>
/// Called when a player gains score in Snake.
/// </summary>
/// <param name="ev">The <see cref="GainedScoreEventArgs"/> instance.</param>
public static void OnGainedScore(GainedScoreEventArgs ev)
{
GainedScore.InvokeSafely(ev);
}

/// <summary>
/// Called when a player loses in Snake.
/// </summary>
/// <param name="ev">The <see cref="GameOverEventArgs"/> instance.</param>
public static void OnGameOver(GameOverEventArgs ev)
{
GameOver.InvokeSafely(ev);
}

/// <summary>
/// Called when a player starts a new game in Snake.
/// </summary>
/// <param name="ev">The <see cref="NewGameEventArgs"/> instance.</param>
public static void OnNewGame(NewGameEventArgs ev)
{
NewGame.InvokeSafely(ev);
}
}
}
61 changes: 61 additions & 0 deletions EXILED/Exiled.Events/Patches/Events/Snake/ChaosKeycard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// -----------------------------------------------------------------------
// <copyright file="ChaosKeycard.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.Patches.Events.Snake
{
using System.Collections.Generic;
using System.Reflection.Emit;

using Attributes;
using Exiled.API.Features.Items;
using HarmonyLib;
using InventorySystem.Items.Keycards;
using InventorySystem.Items.Keycards.Snake;

using static HarmonyLib.AccessTools;

/// <summary>
/// Patches <see cref="ChaosKeycardItem.ServerProcessCustomCmd" />.
/// </summary>
[EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.GainedScore))]
[EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.GameOver))]
[EventPatch(typeof(Handlers.Snake), nameof(Handlers.Snake.NewGame))]
[HarmonyPatch(typeof(ChaosKeycardItem), nameof(ChaosKeycardItem.ServerProcessCustomCmd))]
internal static class ChaosKeycard
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
CodeMatcher matcher = new CodeMatcher(instructions)
.MatchEndForward(new CodeMatch(OpCodes.Ldc_I4_1))
.Advance(-1)
.Insert(
new(OpCodes.Ldarg_0),
new(OpCodes.Ldloc_1),
new(OpCodes.Call, Method(typeof(ChaosKeycard), nameof(OnCardUse))));

return matcher.InstructionEnumeration();
}

private static void OnCardUse(ChaosKeycardItem itemBase, SnakeNetworkMessage message)
{
Keycard item = Item.Get<Keycard>(itemBase);
API.Features.Player player = item.Owner;

if (!ChaosKeycardItem.SnakeSessions.TryGetValue(item.Serial, out SnakeEngine engine))
return;

bool isNewGame = message.HasFlag(SnakeNetworkMessage.SyncFlags.GameReset);

if(message.HasFlag(SnakeNetworkMessage.SyncFlags.HasNewFood) && !isNewGame)
Handlers.Snake.OnGainedScore(new (engine, player, item));
else if (message.HasFlag(SnakeNetworkMessage.SyncFlags.GameOver))
Handlers.Snake.OnGameOver(new(engine, player, item));
else if (isNewGame)
Handlers.Snake.OnNewGame(new(engine, player, item));
}
}
}