mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-01 05:49:23 +00:00
push broken mod
This commit is contained in:
parent
742f816d3d
commit
344e3bb6d6
12 changed files with 500 additions and 0 deletions
43
ChatBoxExtensions/ChatBoxExtensions.csproj
Normal file
43
ChatBoxExtensions/ChatBoxExtensions.csproj
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>..\_ManagedLibs\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\_ManagedLibs\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>..\_ManagedLibs\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ChatBox">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\ChatBox.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>..\_ManagedLibs\MelonLoader.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ml_prm">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\ml_prm.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\_ManagedLibs\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>..\_ManagedLibs\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Deploy" AfterTargets="Build">
|
||||
<Copy SourceFiles="$(TargetPath)" DestinationFolder="C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" />
|
||||
<Message Text="Copied $(TargetPath) to C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\" Importance="high" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
25
ChatBoxExtensions/ChatBoxExtensions.sln
Normal file
25
ChatBoxExtensions/ChatBoxExtensions.sln
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32630.192
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatBoxExtensions", "ChatBoxExtensions.csproj", "{319281C7-C2CC-4350-ACE9-A52467C3E1EF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{319281C7-C2CC-4350-ACE9-A52467C3E1EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{319281C7-C2CC-4350-ACE9-A52467C3E1EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{319281C7-C2CC-4350-ACE9-A52467C3E1EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{319281C7-C2CC-4350-ACE9-A52467C3E1EF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {67285FB2-B0B0-44AF-AC34-C47B3BF054ED}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
14
ChatBoxExtensions/HarmonyPatches.cs
Normal file
14
ChatBoxExtensions/HarmonyPatches.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using ABI_RC.Core.Savior;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.HarmonyPatches;
|
||||
|
||||
public class CVRInputManagerPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(CVRInputManager), "Start")]
|
||||
static void Postfix_CVRInputManager_Start(ref CVRInputManager __instance)
|
||||
{
|
||||
ChatBoxExtensions.InputModule = __instance.gameObject.AddComponent<InputModules.InputModuleChatBoxExtensions>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using ABI_RC.Core.Savior;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.InputModules;
|
||||
|
||||
internal class InputModuleChatBoxExtensions : CVRInputModule
|
||||
{
|
||||
public bool jump = false;
|
||||
public float emote = -1;
|
||||
public Vector2 lookVector = Vector2.zero;
|
||||
public Vector3 movementVector = Vector3.zero;
|
||||
|
||||
public override void UpdateInput()
|
||||
{
|
||||
CVRInputManager.Instance.jump |= jump;
|
||||
CVRInputManager.Instance.movementVector += movementVector;
|
||||
CVRInputManager.Instance.lookVector += lookVector;
|
||||
if (emote > 0) CVRInputManager.Instance.emote = emote;
|
||||
|
||||
jump = false;
|
||||
emote = -1;
|
||||
lookVector = Vector3.zero;
|
||||
movementVector = Vector3.zero;
|
||||
}
|
||||
}
|
56
ChatBoxExtensions/Integrations/Base.cs
Normal file
56
ChatBoxExtensions/Integrations/Base.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.Integrations;
|
||||
|
||||
public class CommandBase
|
||||
{
|
||||
internal static bool IsCommandForAll(string argument)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(argument)) return false;
|
||||
return argument == "*" || argument.StartsWith("@a") || argument.StartsWith("@e");
|
||||
}
|
||||
|
||||
internal static bool IsCommandForLocalPlayer(string argument)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(argument)) return false;
|
||||
if (argument.Contains("*"))
|
||||
{
|
||||
string partialName = argument.Replace("*", "").Trim();
|
||||
if (String.IsNullOrWhiteSpace(partialName)) return false;
|
||||
return MetaPort.Instance.username.Contains(partialName);
|
||||
}
|
||||
return MetaPort.Instance.username == argument;
|
||||
}
|
||||
|
||||
internal static void LocalCommandIgnoreOthers(string argument, Action<string[]> callback)
|
||||
{
|
||||
string[] args = argument.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToArray();
|
||||
|
||||
// will fail if arguments are specified which arent local player
|
||||
if (args.Length == 0 || IsCommandForAll(args[0]) || IsCommandForLocalPlayer(args[0])) callback(args);
|
||||
}
|
||||
|
||||
//remote must specify exact player, wont respawn to all
|
||||
internal static void RemoteCommandListenForSelf(string argument, Action<string[]> callback)
|
||||
{
|
||||
string[] args = argument.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToArray();
|
||||
|
||||
if (args.Length == 0) return;
|
||||
if (IsCommandForLocalPlayer(args[0])) callback(args);
|
||||
}
|
||||
|
||||
// remote must specify player or all, ignore commands without arguments
|
||||
internal static void RemoteCommandListenForAll(string argument, Action<string[]> callback)
|
||||
{
|
||||
string[] args = argument.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToArray();
|
||||
|
||||
if (args.Length == 0) return;
|
||||
if (IsCommandForAll(args[0]) || IsCommandForLocalPlayer(args[0])) callback(args);
|
||||
}
|
||||
|
||||
internal static string GetPlayerUsername(string guid)
|
||||
{
|
||||
return CVRPlayerManager.Instance.TryGetPlayerName(guid);
|
||||
}
|
||||
}
|
43
ChatBoxExtensions/Integrations/ChatBox.cs
Normal file
43
ChatBoxExtensions/Integrations/ChatBox.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using Kafe.ChatBox;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.Integrations;
|
||||
|
||||
internal class ChatBoxCommands : CommandBase
|
||||
{
|
||||
public static void RegisterCommands()
|
||||
{
|
||||
bool awaitingPing = false;
|
||||
DateTime pingTime = DateTime.MinValue; // store the time when "ping" command was sent
|
||||
|
||||
Commands.RegisterCommand("ping",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
pingTime = DateTime.Now;
|
||||
awaitingPing = true;
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForSelf(message, args =>
|
||||
{
|
||||
ChatBox.SendMessage("/pong " + GetPlayerUsername(sender), false);
|
||||
});
|
||||
});
|
||||
|
||||
Commands.RegisterCommand("pong",
|
||||
onCommandSent: null,
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForSelf(message, args =>
|
||||
{
|
||||
if (awaitingPing)
|
||||
{
|
||||
awaitingPing = false;
|
||||
TimeSpan timeSincePing = DateTime.Now - pingTime; // calculate the time difference
|
||||
ChatBox.SendMessage($"Time since ping: {timeSincePing.TotalMilliseconds}ms", false);
|
||||
return;
|
||||
}
|
||||
ChatBox.SendMessage($"You have to ping first, {GetPlayerUsername(sender)}!", false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
43
ChatBoxExtensions/Integrations/ChilloutVRBase.cs
Normal file
43
ChatBoxExtensions/Integrations/ChilloutVRBase.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.Base;
|
||||
using Kafe.ChatBox;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.Integrations;
|
||||
|
||||
internal class ChilloutVRBaseCommands : CommandBase
|
||||
{
|
||||
public static void RegisterCommands()
|
||||
{
|
||||
Commands.RegisterCommand("respawn",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, args =>
|
||||
{
|
||||
RootLogic.Instance.Respawn();
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, (args) =>
|
||||
{
|
||||
RootLogic.Instance.Respawn();
|
||||
});
|
||||
});
|
||||
|
||||
Commands.RegisterCommand("mute",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, args =>
|
||||
{
|
||||
Audio.SetMicrophoneActive(true);
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, args =>
|
||||
{
|
||||
Audio.SetMicrophoneActive(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
58
ChatBoxExtensions/Integrations/ChilloutVRInput.cs
Normal file
58
ChatBoxExtensions/Integrations/ChilloutVRInput.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using ABI_RC.Core;
|
||||
using ABI_RC.Core.Base;
|
||||
using ABI_RC.Core.Savior;
|
||||
using Kafe.ChatBox;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.Integrations;
|
||||
|
||||
internal class ChilloutVRInputCommands : CommandBase
|
||||
{
|
||||
public static void RegisterCommands()
|
||||
{
|
||||
Commands.RegisterCommand("emote",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, args =>
|
||||
{
|
||||
if (args.Length > 0 && int.TryParse(args[0], out int emote))
|
||||
{
|
||||
ChatBoxExtensions.InputModule.emote = (float)emote;
|
||||
}
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, args =>
|
||||
{
|
||||
if (args.Length > 1 && int.TryParse(args[1], out int emote))
|
||||
{
|
||||
ChatBoxExtensions.InputModule.emote = (float)emote;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Commands.RegisterCommand("jump",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, args =>
|
||||
{
|
||||
if (args.Length > 0 && bool.TryParse(args[0], out bool jump))
|
||||
{
|
||||
ChatBoxExtensions.InputModule.jump = jump;
|
||||
return;
|
||||
}
|
||||
ChatBoxExtensions.InputModule.jump = true;
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, args =>
|
||||
{
|
||||
if (bool.TryParse(args[0], out bool jump))
|
||||
{
|
||||
ChatBoxExtensions.InputModule.jump = jump;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
90
ChatBoxExtensions/Integrations/PlayerRagdollMod.cs
Normal file
90
ChatBoxExtensions/Integrations/PlayerRagdollMod.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using Kafe.ChatBox;
|
||||
using ml_prm;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions.Integrations;
|
||||
|
||||
internal class PlayerRagdollModCommands : CommandBase
|
||||
{
|
||||
public static void RegisterCommands()
|
||||
{
|
||||
Commands.RegisterCommand("unragdoll",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, (args) =>
|
||||
{
|
||||
if (RagdollController.Instance.IsRagdolled())
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, (args) =>
|
||||
{
|
||||
if (RagdollController.Instance.IsRagdolled())
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Commands.RegisterCommand("ragdoll",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, (args) =>
|
||||
{
|
||||
bool switchRagdoll = true;
|
||||
|
||||
if (args.Length > 0 && bool.TryParse(args[0], out bool state))
|
||||
{
|
||||
switchRagdoll = state != RagdollController.Instance.IsRagdolled();
|
||||
}
|
||||
|
||||
if (switchRagdoll)
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, (args) =>
|
||||
{
|
||||
bool switchRagdoll = true;
|
||||
|
||||
if (args.Length > 1 && bool.TryParse(args[1], out bool state))
|
||||
{
|
||||
switchRagdoll = state != RagdollController.Instance.IsRagdolled();
|
||||
}
|
||||
|
||||
if (switchRagdoll)
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Commands.RegisterCommand("kill",
|
||||
onCommandSent: (message, sound) =>
|
||||
{
|
||||
LocalCommandIgnoreOthers(message, (args) =>
|
||||
{
|
||||
if (!RagdollController.Instance.IsRagdolled())
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
},
|
||||
onCommandReceived: (sender, message, sound) =>
|
||||
{
|
||||
RemoteCommandListenForAll(message, (args) =>
|
||||
{
|
||||
if (!RagdollController.Instance.IsRagdolled())
|
||||
{
|
||||
RagdollController.Instance.SwitchRagdoll();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
48
ChatBoxExtensions/Main.cs
Normal file
48
ChatBoxExtensions/Main.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using MelonLoader;
|
||||
using NAK.Melons.ChatBoxExtensions.InputModules;
|
||||
|
||||
namespace NAK.Melons.ChatBoxExtensions;
|
||||
|
||||
public class ChatBoxExtensions : MelonMod
|
||||
{
|
||||
internal static MelonLogger.Instance Logger;
|
||||
internal static InputModuleChatBoxExtensions InputModule;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
|
||||
if (!MelonMod.RegisteredMelons.Any(it => it.Info.Name == "ChatBox"))
|
||||
{
|
||||
Logger.Error("ChatBox was not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyIntegrations();
|
||||
}
|
||||
|
||||
void ApplyIntegrations()
|
||||
{
|
||||
Integrations.ChatBoxCommands.RegisterCommands();
|
||||
Integrations.ChilloutVRBaseCommands.RegisterCommands();
|
||||
ApplyPatches(typeof(HarmonyPatches.CVRInputManagerPatches));
|
||||
|
||||
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "PlayerRagdollMod"))
|
||||
{
|
||||
Integrations.PlayerRagdollModCommands.RegisterCommands();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyPatches(Type type)
|
||||
{
|
||||
try
|
||||
{
|
||||
HarmonyInstance.PatchAll(type);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Msg($"Failed while patching {type.Name}!");
|
||||
Logger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
32
ChatBoxExtensions/Properties/AssemblyInfo.cs
Normal file
32
ChatBoxExtensions/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using ChatBoxExtensions.Properties;
|
||||
using MelonLoader;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||
[assembly: AssemblyTitle(nameof(NAK.Melons.ChatBoxExtensions))]
|
||||
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||
[assembly: AssemblyProduct(nameof(NAK.Melons.ChatBoxExtensions))]
|
||||
|
||||
[assembly: MelonInfo(
|
||||
typeof(NAK.Melons.ChatBoxExtensions.ChatBoxExtensions),
|
||||
nameof(NAK.Melons.ChatBoxExtensions),
|
||||
AssemblyInfoParams.Version,
|
||||
AssemblyInfoParams.Author,
|
||||
downloadLink: "https://github.com/NotAKidOnSteam/ChatBoxExtensions"
|
||||
)]
|
||||
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||
[assembly: MelonOptionalDependencies("ChatBox", "PlayerRagdollMod")]
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
|
||||
namespace ChatBoxExtensions.Properties;
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
||||
public const string Author = "NotAKidoS";
|
||||
}
|
23
ChatBoxExtensions/format.json
Normal file
23
ChatBoxExtensions/format.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"_id": 129,
|
||||
"name": "ChatBoxExtensions",
|
||||
"modversion": "1.0.1",
|
||||
"gameversion": "2022r170",
|
||||
"loaderversion": "0.5.7",
|
||||
"modtype": "Mod",
|
||||
"author": "NotAKidoS",
|
||||
"description": "Prevents VRIK from using toe bones in VR & optionaly FBT.\n\nVRIK calculates weird center of mass when toes are mapped, so it is sometimes desired to unmap toes to prevent an avatars feet from resting far back.\n\nPlease see the README for relevant imagery detailing the problem.",
|
||||
"searchtags": [
|
||||
"toes",
|
||||
"vrik",
|
||||
"ik",
|
||||
"feet"
|
||||
],
|
||||
"requirements": [
|
||||
"None"
|
||||
],
|
||||
"downloadlink": "https://github.com/NotAKidOnSteam/ChatBoxExtensions/releases/download/v1.0.1/ChatBoxExtensions.dll",
|
||||
"sourcelink": "https://github.com/NotAKidOnSteam/ChatBoxExtensions/",
|
||||
"changelog": "- Initial Release\n- No double patching. Bad. Stinky. Dont do it.",
|
||||
"embedcolor": "#ffc700"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue