Skip to content

Commit

Permalink
UGC twitch message thing
Browse files Browse the repository at this point in the history
add dead pixel and detach seatruck segment
try (in vain) to reduce ermfish fps impact
  • Loading branch information
Govorunb committed Jun 15, 2024
1 parent 4f775aa commit c49026f
Show file tree
Hide file tree
Showing 24 changed files with 569 additions and 72 deletions.
51 changes: 51 additions & 0 deletions SCHIZO/Commands/DevCommands.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using SCHIZO.Commands.Attributes;
using SCHIZO.Commands.Input;
using SCHIZO.Commands.Output;
using SCHIZO.Helpers;
using SCHIZO.Tweaks;
Expand Down Expand Up @@ -87,4 +90,52 @@ public static void DevMode()
else
Player.main.gameObject.AddComponent<DevBinds>();
}

[Command(Name = "_get",
DisplayName = "Get static member",
Description = "Get value of a static member",
RegisterConsoleCommand = true)]
public static object PrintField(string typeName, string memberName)
{
Type type = ReflectionCache.GetType(typeName);
if (type is null) return $"Could not find type '{typeName}'";
MemberInfo[] member = type.GetMember(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
if (member is null) return $"Could not find '{memberName}' in type '{typeName}' (must be static)";
return ReflectionHelpers.GetStaticMemberValue<object>(member.Single());
}

[Command(Name = "_set",
DisplayName = "Set static member",
Description = "Set value of a static member",
RegisterConsoleCommand = true)]
public static object SetField(string typeName, string memberName, string valueStr)
{
Type type = ReflectionCache.GetType(typeName);
if (type is null) return $"Could not find type '{typeName}'";
MemberInfo member = type.GetMember(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Single();
if (member is null) return $"Could not find '{memberName}' in type '{typeName}' (must be static)";
Type memberType = member switch
{
PropertyInfo p => p.PropertyType,
FieldInfo f => f.FieldType,
_ => null
};
if (memberType is null) return $"'{memberName}' is not a property or field";

if (!Conversion.TryParseOrConvert(valueStr, memberType, out object value))
{
return $"Could not convert '{valueStr}' to type '{memberType}'";
}
switch (member)
{
case PropertyInfo prop:
prop.SetValue(null, value);
return null;
case FieldInfo field:
field.SetValue(null, value);
return null;
default:
throw new InvalidOperationException("Unreachable");
}
}
}
3 changes: 2 additions & 1 deletion SCHIZO/Resources/AssetBundles/Assets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace SCHIZO.Resources;

public static class Assets
{
private const int _rnd = 2142497487;
private const int _rnd = -1269642852;

private static readonly UnityEngine.AssetBundle _a = ResourceManager.GetAssetBundle("assets");

Expand All @@ -26,5 +26,6 @@ public static class Assets
public static SCHIZO.Options.Bool.ToggleModOption Mod_Options_EnableAutomaticEvents = _a.LoadAsset<SCHIZO.Options.Bool.ToggleModOption>("Assets/Mod/Options/Enable automatic events.asset");
public static SCHIZO.Options.Button.ButtonModOption Mod_Options_SwarmControl = _a.LoadAsset<SCHIZO.Options.Button.ButtonModOption>("Assets/Mod/Options/Swarm Control.asset");
public static SCHIZO.Registering.ModRegistry Mod_Registry = _a.LoadAsset<SCHIZO.Registering.ModRegistry>("Assets/Mod/Registry.asset");
public static UnityEngine.GameObject Mod_SwarmControl_DeadPixel = _a.LoadAsset<UnityEngine.GameObject>("Assets/Mod/Swarm Control/DeadPixel.prefab");
public static UnityEngine.Material Mod_VFX_ARGCensor_ARGcensorMat = _a.LoadAsset<UnityEngine.Material>("Assets/Mod/VFX/ARG Censor/ARGcensor_mat.mat");
}
Binary file modified SCHIZO/Resources/AssetBundles/assets
Binary file not shown.
29 changes: 29 additions & 0 deletions SCHIZO/SwarmControl/Redeems/Annoying/DeadPixelRedeem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Collections.Generic;
using SCHIZO.Commands.Base;
using SCHIZO.Commands.Context;
using SCHIZO.Resources;
using UnityEngine;

namespace SCHIZO.SwarmControl.Redeems.Annoying;
#nullable enable

[Redeem(
Name = "redeem_deadpixel",
DisplayName = "Dead Pixel",
Description = "The whole screen is your canvas... Lasts 5 minutes"
)]
internal class DeadPixelRedeem : Command, IParameters
{
public static float Duration = 300f;
public IReadOnlyList<Parameter> Parameters => [];

protected override object? ExecuteCore(CommandExecutionContext ctx)
{
Vector2 coords = new(Random.Range(0, 1920), Random.Range(0, 1080));
GameObject instance = GameObject.Instantiate(Assets.Mod_SwarmControl_DeadPixel);
instance.EnsureComponent<DeadPixel>().duration = Duration;
instance.transform.SetParent(uGUI.main.screenCanvas.transform, false);
instance.transform.localPosition = new Vector2(coords.x-960, coords.y-540);
return $"Your pixel is at {coords}";
}
}
38 changes: 38 additions & 0 deletions SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Collections.Generic;
using SCHIZO.Commands.Base;
using SCHIZO.Commands.Context;
using SCHIZO.Commands.Output;
using UnityEngine;

namespace SCHIZO.SwarmControl.Redeems.Annoying;

#nullable enable
[Redeem(
Name = "redeem_detach",
DisplayName = "Bad Glue",
Description = "Whoever designed the Sea Truck module connector should be fired..."
)]
internal class DetachBackSeatruckModule : Command, IParameters
{
public IReadOnlyList<Parameter> Parameters => [];

protected override object? ExecuteCore(CommandExecutionContext ctx)
{
if (!Player.main) return CommonResults.Error("Requires a loaded game.");

SeaTruckUpgrades cabin = GameObject.FindObjectOfType<SeaTruckUpgrades>();

Check failure on line 23 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckUpgrades' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 23 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckUpgrades' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 23 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckUpgrades' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 23 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckUpgrades' could not be found (are you missing a using directive or an assembly reference?)
if (!cabin) return CommonResults.Error("Sea Truck not found.");

SeaTruckSegment cabinSegment = cabin.GetComponent<SeaTruckSegment>();

Check failure on line 26 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 26 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)
SeaTruckSegment rearSegment = cabinSegment;

Check failure on line 27 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 27 in SCHIZO/SwarmControl/Redeems/Annoying/DetachBackSeatruckModule.cs

View workflow job for this annotation

GitHub Actions / build (Subnautica)

The type or namespace name 'SeaTruckSegment' could not be found (are you missing a using directive or an assembly reference?)
while (rearSegment.rearConnection && rearSegment.rearConnection.connection)
rearSegment = rearSegment.rearConnection.connection.truckSegment;

if (rearSegment == cabinSegment)
return CommonResults.Error("Sea Truck not connected to any modules.");

rearSegment.Detach();

return CommonResults.OK();
}
}
10 changes: 5 additions & 5 deletions SCHIZO/SwarmControl/Redeems/Annoying/ShowNotif.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
using SCHIZO.Commands.Output;

namespace SCHIZO.SwarmControl.Redeems.Annoying;
#nullable enable

#nullable enable
[Redeem(
Name = "redeem_notif",
DisplayName = "Ping Alex",
Expand All @@ -24,10 +24,10 @@ internal class ShowNotif : Command, IParameters
"OperationCanceledException: The operation was canceled.",
"The parameter is incorrect",
"""
System.Net.WebSockets.WebSocketException (0x80004005): The 'System.Net.WebSockets.ServerWebSocket' instance cannot be used for communication because it has been transitioned into the 'Aborted' state.
---> System.Net.WebSockets.WebSocketException (0x80004005): An internal WebSocket error occurred. Please see the innerException, if present, for more details. ---> System.Net.HttpListenerException (0x80004005): An operation was attempted on a nonexistent network connection
at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.d__9.MoveNext()
System.Net.WebSockets.WebSocketException (0x80004005): The 'System.Net.WebSockets.ClientWebSocket' instance cannot be used for communication because it has been transitioned into the 'Aborted' state.
---> System.Net.WebSockets.WebSocketException (0x80004005): An internal WebSocket error occurred. Please see the innerException, if present, for more details. ---> System.Net.HttpClientException (0x80004005): An operation was attempted on a nonexistent network connection
at System.Net.WebSockets.WebSocketHttpClientDuplexStream.WriteAsyncFast(HttpClientAsyncEventArgs eventArgs)
at System.Net.WebSockets.WebSocketHttpClientDuplexStream.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Expand Down
2 changes: 1 addition & 1 deletion SCHIZO/SwarmControl/Redeems/Misc/BigErm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace SCHIZO.SwarmControl.Redeems.Misc;
#nullable enable
[Redeem(Name = "redeem_bigerm",
DisplayName = "Big Erm",
Description = "It's time to Get Big"
Description = "The Erm Moon sends its regards"
)]
internal class BigErm : Command, IParameters
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
using System.Collections;
using System.Collections.Generic;
using SCHIZO.Commands.Base;
using SCHIZO.Commands.Context;
using SCHIZO.Commands.Input;
using SCHIZO.Commands.Output;
using SCHIZO.Twitch;
using SwarmControl.Models.Game.Messages;
using UnityEngine;
using UWE;

namespace SCHIZO.SwarmControl.Redeems.PayAttentionToMeStreamer;

#nullable enable
[Redeem(
Name = "redeem_addsignal",
DisplayName = "Add Beacon",
Description = "Adds a beacon ping to the map."
DisplayName = "Add Signal",
Description = "Adds a signal marker to the world. After redeeming, your next Twitch chat message will name the beacon."
)]
internal class AddSignalRedeem() : ProxyCommand<MethodCommand>("addsignal")
internal class AddSignalRedeem : Command, IParameters
{
public override IReadOnlyList<Parameter> Parameters { get; } = [
new Parameter(new("coords", "Coordinates", "Beacon coordinates"), typeof(Vector3), false),
new Parameter(new("name", "Name", "Beacon name"), typeof(string), false)
public IReadOnlyList<Parameter> Parameters { get; } = [
new Parameter(new("coords", "Coordinates", "Beacon coordinates"), typeof(Vector3), false)
];

protected override Dictionary<string, object?>? GetTargetArgs(Dictionary<string, object?>? proxyArgs)
protected override object? ExecuteCore(CommandExecutionContext ctx)
{
if (proxyArgs is null) return [];

NamedArgs args = new(proxyArgs);
Dictionary<string, object?> targetArgs = [];
if (!args.TryGetValue("coords", out Vector3 coords) || !args.TryGetValue("name", out string? name))
return targetArgs;
RedeemMessage? model = (ctx.Input as RemoteInput)?.Model;
TwitchUser? user = model?.User;
if (user is null)
return CommonResults.Error("Could not get user");
if (!ctx.Input.GetNamedArguments().TryGetValue("coords", out Vector3 coords))
return CommonResults.Error("Invalid coordinates");
CoroutineHost.StartCoroutine(Coro(user, coords));
return "Success - the next message you send in Twitch chat will be used to name the beacon.";
}

return new()
{
{ "x", coords.x },
{ "y", coords.y },
{ "z", coords.z },
{ "signalName", name }
};
private IEnumerator Coro(TwitchUser user, Vector3 coords)
{
string? message = null;
TwitchIntegration.AddNextMessageCallback(user, (msg) => message = msg ?? "(unnamed)");
yield return new WaitUntil(() => message is { });
CustomSignalManager.AddSignal(coords.x, coords.y, coords.z,
$"[{user.DisplayName}]\n{message}");
}
}
48 changes: 22 additions & 26 deletions SCHIZO/SwarmControl/Redeems/PayAttentionToMeStreamer/Hint.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using SCHIZO.Commands;
using SCHIZO.Commands.Base;
using SCHIZO.Commands.Context;
using SCHIZO.Commands.Input;
using SwarmControl.Models.Game;
using SCHIZO.Commands.Output;
using SwarmControl.Models.Game.Messages;
using UnityEngine;
using UWE;

namespace SCHIZO.SwarmControl.Redeems.PayAttentionToMeStreamer;

#nullable enable
[Redeem(
Name = "redeem_hint",
DisplayName = "Send Hint",
Description = "Display a message in the center of the screen",
DisplayName = "Send Message",
Description = "Your next Twitch chat message will be displayed in-game",
Announce = false // the message itself is the announcement
)]
internal class Hint() : ProxyCommand<MethodCommand>("hint")
internal class Hint : Command, IParameters
{
public override IReadOnlyList<Parameter> Parameters => [
new TextParameter(new NamedModel("message", "Message", "The message to display")) {
MinLength = 1
}
];
public IReadOnlyList<Parameter> Parameters => [];

protected override JsonContext GetContextForTarget(JsonContext proxyCtx)
protected override object? ExecuteCore(CommandExecutionContext ctx)
{
RemoteInput input = proxyCtx.JsonInput;
input.Model.Announce = false;
string submitter = input.Model.GetDisplayName();
NamedArgs args = input.GetNamedArguments();
args.TryGetValue("message", out string? message);
if (string.IsNullOrWhiteSpace(message))
message = "(no message)";
args["message"] = $"{submitter}: {message}";
return base.GetContextForTarget(proxyCtx);
RedeemMessage? model = (ctx.Input as RemoteInput)?.Model;
TwitchUser? user = model?.User;
if (user is null)
return CommonResults.Error("Could not get user");
CoroutineHost.StartCoroutine(Coro(user));
return "Success - the next message you send in Twitch chat will be displayed in-game.";
}

protected override Dictionary<string, object?> GetTargetArgs(Dictionary<string, object?>? proxyArgs)
private IEnumerator Coro(TwitchUser user)
{
if (proxyArgs is null) return [];

return new Dictionary<string, object?>
{
{ "message", proxyArgs["message"] }
};
string? message = null;
Twitch.TwitchIntegration.AddNextMessageCallback(user, (msg) => message = msg ?? "(no message)");
yield return new WaitUntil(() => message is { });
DevCommands.Hint($"{user.DisplayName}: {message}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ protected override object ExecuteCore(CommandExecutionContext ctx)
.Select(tag => tag.gameObject)
.FirstOrDefault(erm =>
{
NameTag tag = erm.GetComponentInChildren<NameTag>();
if (!tag) return false;
if (!string.IsNullOrWhiteSpace(tag.textMesh.text)) return false;

return true;
NameTag tag = erm.GetComponentInChildren<NameTag>(true);
return tag && !tag.isActiveAndEnabled;
});

RemoteInput? input = ctx.Input as RemoteInput;
Expand Down Expand Up @@ -91,10 +88,10 @@ private IEnumerator SpawnCoro(string? user)

private void SetNameTag(GameObject ermfish, string? user)
{
NameTag tag = ermfish.GetComponentInChildren<NameTag>();
if (!tag) return;
if (!string.IsNullOrWhiteSpace(tag.textMesh.text)) return;
NameTag tag = ermfish.GetComponentInChildren<NameTag>(true);
if (!tag || tag.isActiveAndEnabled) return;

tag.textMesh.text = user;
tag.gameObject.SetActive(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace SCHIZO.SwarmControl.Redeems.PayAttentionToMeStreamer;
Name = "redeem_say",
DisplayName = "Send Text",
Description = "Display text in the top left of the screen",
Export = false, /// deprecated in favor of <see cref="Hint"/>
Announce = false // the message itself is the announcement
)]
internal class Say() : ProxyCommand<MethodCommand>("say")
Expand Down
23 changes: 15 additions & 8 deletions SCHIZO/SwarmControl/SwarmControlManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,17 @@ private static void SetKey(string key)
}

[Command(Name = "sc_rc", RegisterConsoleCommand = true)]
private static void ManualReconnect()
private static void ManualReconnectCommand()
{
Task.Run(async () =>
{
await Instance._socket.Disconnect();
if (!await Instance._socket.ConnectSocket())
LOGGER.LogError("Manual reconnect failed");
});
_ = Instance.ManualReconnect();
}

private async Task ManualReconnect()
{
await _socket.Disconnect();
if (!await _socket.ConnectSocket())
QueueOnMainThread(() => LOGGER.LogWarning("Manual reconnect failed"));
_reconnectCoro ??= StartCoroutine(AutoReconnectCoro());
}

private void ButtonPressed()
Expand Down Expand Up @@ -161,7 +164,11 @@ private IEnumerator ConnectCoro(CancellationToken ct)

private void Disconnect()
{
if (_reconnectCoro is { }) StopCoroutine(_reconnectCoro);
if (_reconnectCoro is { })
{
StopCoroutine(_reconnectCoro);
_reconnectCoro = null;
}
if (!_socket.IsConnected) return;
StartCoroutine(DisconnectCoro());
}
Expand Down
Loading

0 comments on commit c49026f

Please sign in to comment.