Skip to content
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
54 changes: 25 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

- 在游戏原版资源之外加载迷彩。
- 在游戏原版资源之外加载武器。
- 运行自定义脚本呢来扩展游戏功能
- 在游戏根目录下生成`DebugEmit`文件夹提供Mod开发所需的一些资料。
- 更多特性正在开发中……

Expand Down Expand Up @@ -49,39 +50,34 @@
在每一个Mod文件夹之下,都有一定的文件结构来表示Mod,比如:

Mod文件夹

|-sfh

|--camos

|---Red1

|----texture.png

|----icon.png

|----redCamo.png

|--weapons

|----equipTexture.png

|----equipTextureAlt.png

|----menuTexture.png

|----unequipTexture.png

|mod.json

- `sfh`:所有原版数据和资产都在这个文件夹(你也可以定制你自己的文件夹名,比如说xxddc之类的,但sfh被指定为原版的文件夹,又称**命名空间**)下,更改这个命名空间下的文件说明你将覆盖原版的数据和资产。
- (Mod根目录)
- sfh
- camos
- Red1
- texture.png
- icon.png
- redCamo.pn
- weapons
- equipTexture.png
- equipTextureAlt.png
- menuTexture.png
- unequipTexture.png
- mymod
- scripts
- index.js
- mod.json

- `sfh`:所有原版数据和资产都在这个文件夹(你也可以定制你自己的文件夹名,比如说`xxddc`之类的,但`sfh`被指定为原版的文件夹,又称**命名空间**)下,更改这个命名空间下的文件说明你将覆盖原版的数据和资产。
- `camos`:迷彩文件夹,其下每一个文件夹代表一个与之名称相同的迷彩
- `Red1`:这是原版的“邪恶”迷彩,内部名称为`Red1`
- `Red1`:这是原版的“邪恶”迷彩,内部名称为`Red1`。你可以将其更换为
- `texture.png`:这是人物贴图文件
- `icon.png`:这是人物图标文件
- `redCamo.png`:这是迷彩层文件
- `weapons`:武器文件夹,其下每一个文件夹代表一个与之名称相同的武器
- `weapons`文件夹下每一个贴图代表了武器的某种状态的贴图,目前只能确定`equipTexture.png`是装备在人物身上时显示的贴图。
- `weapons`文件夹下每一个贴图代表了武器的某种状态的贴图,目前只能确定`equipTexture.png`是装备在人物身上时显示的贴图,其他贴图请自行尝试。
- `mymod`文件夹是和`sfh`平行的命名空间,其中`mymod`替换为你的mod名称。一般来说,在原版之外新增加的东西应该增加到你专有的mod命名空间当中,比如脚本。
- `scripts`文件夹是存放脚本的文件夹,所有同命名空间的脚本都放置在此文件夹下。
- `index.js`是脚本文件的入口,每个命名空间下的`scripts/index.js`都是各自的脚本执行的入口。其余脚本文件只能被引用,不会被执行。

(更多内容正在开发中……)

Expand All @@ -98,4 +94,4 @@ Mod文件夹

## 许可证

GPL-v3
[**GPL-v3**](./LICENSE)
9 changes: 9 additions & 0 deletions SFHR_ZModLoader.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ItemGroup>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.*" IncludeAssets="compile" />
<PackageReference Include="BepInEx.PluginInfoProps" Version="2.*" />
<PackageReference Include="Jint" Version="3.0.0-beta-2056" />
<!-- <PackageReference Include="Microsoft.ClearScript.V8" Version="7.4.4" /> -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
Expand Down Expand Up @@ -67,5 +68,13 @@
<HintPath>./deps/Il2Cppmscorlib.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>./deps/UnityEngine.UI.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>./deps/UnityEngine.UIModule.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
</Project>
30 changes: 20 additions & 10 deletions scripts/FetchDependencies.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
$gamePath = Resolve-Path $(Get-Content '.gamepath')
$dependencies = @(
"Assembly-CSharp.dll",
"Assembly-CSharp-firstpass.dll",
"Il2Cppmscorlib.dll",
"UnityEngine.dll",
"UnityEngine.InputModule.dll",
"UnityEngine.InputLegacyModule.dll",
"UnityEngine.CoreModule.dll",
"UnityEngine.AudioModule.dll",
"UnityEngine.ImageConversionModule.dll",
"UnityEngine.ImageConversionModule.dll",
"FishNet.Runtime.dll",
"UnityEngine.UI.dll"
"UnityEngine.UIModule.dll"
)

New-Item -ItemType Directory -Path 'deps' -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/Assembly-CSharp.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/Assembly-CSharp.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/Assembly-CSharp-firstpass.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/Assembly-CSharp-firstpass.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/Il2Cppmscorlib.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/Il2Cppmscorlib.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.InputModule.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.InputModule.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.InputLegacyModule.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.InputLegacyModule.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.CoreModule.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.CoreModule.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.AudioModule.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.AudioModule.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/UnityEngine.ImageConversionModule.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/UnityEngine.ImageConversionModule.dll') -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path 'deps/FishNet.Runtime.dll' -Value $(Join-Path -Path $gamePath -ChildPath 'BepInEx/Interop/FishNet.Runtime.dll') -ErrorAction SilentlyContinue

foreach ($dependency in $dependencies) {
New-Item -ItemType SymbolicLink -Path "deps/$dependency" -Value $(Join-Path -Path $gamePath -ChildPath "BepInEx/interop/$dependency") -ErrorAction SilentlyContinue
}
3 changes: 1 addition & 2 deletions scripts/Publish.ps1
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
dotnet publish -c Release -o .\publish
Compress-Archive -Path .\publish\* -Destination publish.zip
dotnet publish -c Release -o .\publish
32 changes: 19 additions & 13 deletions src/EventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using BepInEx.Logging;
using Cpp2IL.Core.Extensions;

namespace SFHR_ZModLoader
{
Expand All @@ -13,7 +14,7 @@ public struct Event

public class EventManager
{
private readonly Dictionary<string, Action<Event>> eventHandlers;
private readonly Dictionary<string, Dictionary<string, Action<Event>>> eventHandlers;
private readonly ManualLogSource logger;

public EventManager(ManualLogSource logger)
Expand All @@ -25,33 +26,38 @@ public EventManager(ManualLogSource logger)
public void EmitEvent(Event ev)
{
logger.LogInfo($"Event: {ev.type}");
foreach(var handler in eventHandlers)
if (eventHandlers.TryGetValue(ev.type, out var handlers))
{
if(handler.Key == ev.type)
foreach (var handler in handlers.Clone())
{
handler.Value(ev);
handler.Value.Invoke(ev);
}
}
}

public void RegisterEventHandler(string type, Action<Event> handler)
public string RegisterEventHandler(string type, Action<Event> handler, string? handlerId = null)
{
if(eventHandlers.TryGetValue(type, out var curHandler))
Dictionary<string, Action<Event>> handlers;
if (eventHandlers.TryGetValue(type, out var _handlers))
{
eventHandlers[type] = ev => {
curHandler(ev);
handler(ev);
};
handlers = _handlers;
}
else
{
eventHandlers[type] = handler;
eventHandlers.Add(type, new());
handlers = eventHandlers[type];
}
var id = handlerId ?? Guid.NewGuid().ToString();
handlers.Add(id, handler);
return id;
}

public void ClearEventHandler(string type)
public void UnregisterEventHandler(string type, string handlerId)
{
eventHandlers.Remove(type);
if (eventHandlers.TryGetValue(type, out var handlers))
{
handlers.Remove(handlerId);
}
}
}
}
36 changes: 29 additions & 7 deletions src/GameContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ namespace SFHR_ZModLoader
{
public class GameContext
{
public GlobalData GlobalData { get; }
public GlobalData? GlobalData { get => GI.GlobalData; }
public ManualLogSource Logger { get; }

public GameContext(GlobalData gd, ManualLogSource logger)
public GameContext(ManualLogSource logger)
{
GlobalData = gd;
Logger = logger;
}

public void PatchCamoData(string name, Action<CamoData> patcher)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Patch CamoData failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Patching CamoData '{name}'...");
var obj = GlobalData.GetItem(name, GI.EItemType.Camo);
if(obj == null)
Expand All @@ -34,15 +37,18 @@ public void PatchCamoData(string name, Action<CamoData> patcher)
patcher(camoData);
Logger.LogInfo($"GameContext: Patch CamoData '{name}' completed.");
}
catch
catch(Exception e)
{
Logger.LogError($"The type is {obj.GetType().Name}");
Logger.LogError($"GameContext: Patch CamoData '{name}' failed.");
Logger.LogWarning($"GameContext: Patch CamoData '{name}' failed: '{e}'.");
}
}

public void PatchWeaponData(string name, Action<WeaponData> patcher)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Patch WeaponData failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Patching WeaponData '{name}'...");
var obj = GlobalData.GetItem(name, GI.EItemType.All);
if(obj == null)
Expand All @@ -58,19 +64,27 @@ public void PatchWeaponData(string name, Action<WeaponData> patcher)
}
catch(Exception e)
{
Logger.LogError($"GameContext: Patch WeaponData '{name}' error: '{e}'.");
Logger.LogWarning($"GameContext: Patch WeaponData '{name}' error: '{e}'.");
}
}

public void InsertTexture(string name, Texture2D newTexture)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Insert Texture failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Inserting Texture '{name}'...");
GlobalData.Textures.Add(name, newTexture);
Logger.LogInfo($"GameContext: Insert Texture '{name}' completed.");
}

public void PatchTexture(string name, Action<Texture2D> patcher, bool fallbackInsert = false)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Patch Texture failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Patching texture '{name}'...");
if (GlobalData.Textures.ContainsKey(name))
{
Expand Down Expand Up @@ -102,13 +116,21 @@ public void PatchTexture(string name, Action<Texture2D> patcher, bool fallbackIn

public void InsertSound(string name, AudioClip newSound)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Insert sound failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Inserting sound '{name}'...");
GlobalData.Sounds.Add(name, newSound);
Logger.LogInfo($"GameContext: Insert sound '{name}' completed.");
}

public void InsertSong(string name, AudioClip newSong)
{
if(GlobalData == null) {
Logger.LogWarning($"GameContext: Insert song failed: GlobalData not loaded.");
return;
}
Logger.LogInfo($"GameContext: Inserting sound '{name}'...");
GlobalData.Songs.Add(name, newSong);
Logger.LogInfo($"GameContext: Insert sound '{name}' completed.");
Expand Down
2 changes: 1 addition & 1 deletion src/Hooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static void Postfix_GlobalData_Load()
if (Logger != null && !isGameContextLoaded)
{
isGameContextLoaded = true;
SFHRZModLoaderPlugin.GameContext = new(globalData, Logger);
SFHRZModLoaderPlugin.GameContext = new(Logger);
EventManager?.EmitEvent(new Event
{
type = "GAMECONTEXT_LOADED",
Expand Down
2 changes: 1 addition & 1 deletion src/InputMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace SFHR_ZModLoader
{
public class InputMonitor: MonoBehaviour
{
private ManualLogSource? Logger { get; set; } = SFHRZModLoaderPlugin.Logger;
private static ManualLogSource? Logger { get; set; } = SFHRZModLoaderPlugin.Logger;
private Dictionary<KeyCode, Action> KeyboradListeners { get; set; }

public InputMonitor()
Expand Down
Loading