Skip to content

Commit 87923d1

Browse files
committed
update: refactor skybox spawn mechanic, fix various critical problem
1 parent c830a92 commit 87923d1

11 files changed

Lines changed: 352 additions & 261 deletions

File tree

EnvManager.cs

Lines changed: 37 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9,67 +9,47 @@ namespace SkyboxChanger;
99

1010
public class EnvManager
1111
{
12-
private string _DefaultPrefab = "";
12+
public string DefaultMaterial { get; set; } = "";
1313

14-
public int _NextSettingPlayer = -1;
15-
public unsafe void OnPlayerJoin(int slot)
14+
public string? CubemapFogPointedSkyName { get; set; } = null;
15+
16+
public Dictionary<int, int> SpawnedSkyboxes = new();
17+
public unsafe void InitializeSkyboxForPlayer(CCSPlayerController player)
1618
{
17-
_NextSettingPlayer = slot;
18-
if (!SkyboxChanger.GetInstance().Config.Skyboxs.ContainsKey(""))
19+
Helper.SpawnSkybox(player.Slot, CubemapFogPointedSkyName ?? "", DefaultMaterial);
20+
21+
Skybox? skybox = SkyboxChanger.GetInstance().Service.GetPlayerSkybox(player);
22+
float brightness = SkyboxChanger.GetInstance().Service.GetPlayerBrightness(player);
23+
Color color = SkyboxChanger.GetInstance().Service.GetPlayerColor(player);
24+
25+
26+
// after 2 tick avoid conflict with SpawnSkybox initialization
27+
Server.NextFrame(() =>
1928
{
20-
foreach (var sky in Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky"))
29+
Server.NextFrame(() =>
2130
{
22-
if (sky.PrivateVScripts == null || sky.PrivateVScripts == "")
23-
{
24-
nint materialptr = *(IntPtr*)sky.SkyMaterial.Value;
25-
var GetMaterialName = VirtualFunction.Create<IntPtr, string>(materialptr, 0);
26-
string skyMaterial = GetMaterialName.Invoke(materialptr);
27-
SkyboxChanger.GetInstance().Config.Skyboxs.Add(
28-
"",
29-
new Skybox { Name = SkyboxChanger.GetInstance().Localizer["menu.defaultskybox"], Material = skyMaterial }
30-
);
31-
break;
32-
}
33-
};
34-
}
35-
Helper.SpawnSkybox(slot, _DefaultPrefab);
31+
Helper.ChangeSkybox(player.Slot, skybox, brightness, color);
32+
});
33+
});
3634
}
3735

3836
public unsafe void OnPlayerLeave(int slot)
3937
{
40-
Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky").ToList().ForEach(sky =>
41-
{
42-
if (sky.PrivateVScripts == slot.ToString())
43-
{
44-
// when killing sky, the material will be released, and if it is used again, the server will crash on map change
45-
// we set it to a not exist material handle to avoid crash
46-
nint ptr = Helper.FindMaterialByPath("materials/notexist.vmat");
47-
Unsafe.Write((void*)sky.SkyMaterial.Handle, ptr);
48-
Unsafe.Write((void*)sky.SkyMaterialLightingOnly.Handle, ptr);
49-
sky.Remove();
50-
}
51-
});
52-
Utilities.FindAllEntitiesByDesignerName<CSkyCamera>("sky_camera").ToList().ForEach(sky =>
53-
{
54-
if (sky.PrivateVScripts == slot.ToString())
55-
{
56-
sky.Remove();
57-
}
58-
});
38+
var index = SpawnedSkyboxes[slot];
39+
CEnvSky sky = Utilities.GetEntityFromIndex<CEnvSky>(index)!;
40+
nint ptr = Helper.FindMaterialByPath("materials/notexist.vmat");
41+
Unsafe.Write((void*)sky.SkyMaterial.Handle, ptr);
42+
Unsafe.Write((void*)sky.SkyMaterialLightingOnly.Handle, ptr);
43+
SpawnedSkyboxes.Remove(slot);
44+
sky.Remove();
5945
}
6046

6147
public void Shutdown()
6248
{
63-
_NextSettingPlayer = -1;
64-
_DefaultPrefab = "";
49+
DefaultMaterial = "";
50+
CubemapFogPointedSkyName = null;
6551
SkyboxChanger.GetInstance().Config.Skyboxs.Remove("");
66-
67-
}
68-
69-
public void SetMapPrefab(string prefab)
70-
{
71-
if (_DefaultPrefab != "") return;
72-
_DefaultPrefab = prefab;
52+
SpawnedSkyboxes.Clear();
7353
}
7454

7555
public bool SetSkybox(int slot, Skybox skybox)
@@ -79,50 +59,27 @@ public bool SetSkybox(int slot, Skybox skybox)
7959

8060
public void SetBrightness(int slot, float value)
8161
{
82-
Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky").ToList().ForEach(sky =>
83-
{
84-
if (slot == -1 || sky.PrivateVScripts == slot.ToString())
85-
{
86-
sky.BrightnessScale = value;
87-
Utilities.SetStateChanged(sky, "CEnvSky", "m_flBrightnessScale");
88-
}
89-
});
62+
Helper.ChangeSkybox(slot, null, value, null);
9063
}
9164

9265
public void SetTintColor(int slot, Color color)
9366
{
94-
Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky").ToList().ForEach(sky =>
95-
{
96-
if (slot == -1 || sky.PrivateVScripts == slot.ToString())
97-
{
98-
sky.TintColor = color;
99-
Utilities.SetStateChanged(sky, "CEnvSky", "m_vTintColor");
100-
}
101-
});
67+
Helper.ChangeSkybox(slot, null, null, color);
10268
}
10369
public void OnCheckTransmit(CCheckTransmitInfoList infoList)
10470
{
105-
var skys = Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky").ToList();
106-
var skycameras = Utilities.FindAllEntitiesByDesignerName<CSkyCamera>("sky_camera").ToList();
10771
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList)
10872
{
10973
if (player == null) continue;
110-
skycameras.ForEach(skyCamera =>
111-
{
112-
if (skyCamera.PrivateVScripts != null && skyCamera.PrivateVScripts != player.Slot.ToString())
113-
{
114-
info.TransmitAlways.Remove(skyCamera.Index);
115-
info.TransmitEntities.Remove(skyCamera.Index);
116-
}
117-
});
118-
skys.ForEach(sky =>
74+
SpawnedSkyboxes.Values.ToList().ForEach(index =>
11975
{
120-
if (sky.PrivateVScripts != player.Slot.ToString())
121-
{
122-
info.TransmitAlways.Remove(sky.Index);
123-
info.TransmitEntities.Remove(sky.Index);
124-
}
76+
info.TransmitAlways.Remove(index);
77+
info.TransmitEntities.Remove(index);
12578
});
79+
if (!SpawnedSkyboxes.ContainsKey(player.Slot)) continue;
80+
var index = SpawnedSkyboxes[player.Slot];
81+
info.TransmitAlways.Add(index);
82+
info.TransmitEntities.Add(index);
12683
}
12784
}
12885
}

Helper.cs

Lines changed: 50 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,15 @@ namespace SkyboxChanger;
1212

1313
public class Helper
1414
{
15-
public static MemoryFunctionVoid<nint, uint, nint, nint, nint>? SpawnPrefabEntities_Windows;
1615

17-
// first param should be double, but ccs doesnt support that and it doesnt matter i think
18-
public static MemoryFunctionWithReturn<nint, float, nint, uint, nint, nint, nint, nint>? SpawnPrefabEntities_Linux;
16+
public static bool IsPlayerSkybox(int slot, CEnvSky sky)
17+
{
18+
return slot == -1 || sky.PrivateVScripts == "skyboxchanger_" + slot;
19+
}
1920

2021
public static void Initialize()
2122
{
22-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
23-
{
24-
SpawnPrefabEntities_Windows = new(GameData.GetSignature("SpawnPrefabEntities"));
25-
SpawnPrefabEntities_Windows.Hook(hook =>
26-
{
27-
string? prefab = KvLib.GetTargetMapName(hook.GetParam<nint>(4));
28-
if (prefab != null)
29-
{
30-
SkyboxChanger.GetInstance().EnvManager.SetMapPrefab(prefab);
31-
}
32-
return HookResult.Continue;
33-
}, HookMode.Pre);
34-
}
35-
else
36-
{
37-
SpawnPrefabEntities_Linux = new(GameData.GetSignature("SpawnPrefabEntities"));
38-
SpawnPrefabEntities_Linux.Hook(hook =>
39-
{
40-
// mismatch with ida
41-
nint ptr = hook.GetParam<nint>(5);
42-
string? prefab = KvLib.GetTargetMapName(ptr);
43-
if (prefab != null)
44-
{
45-
SkyboxChanger.GetInstance().EnvManager.SetMapPrefab(prefab);
46-
}
47-
return HookResult.Continue;
48-
}, HookMode.Pre);
49-
}
23+
5024
}
5125

5226
public static unsafe IntPtr FindMaterialByPath(string material)
@@ -74,60 +48,64 @@ public static unsafe IntPtr FindMaterialByPath(string material)
7448
}
7549
return *(IntPtr*)materialptr3; // CMaterial*** -> CMaterial** (InfoForResourceTypeIMaterial2)
7650
}
77-
public static void SpawnSkybox(int slot, string prefab)
51+
52+
public static unsafe void SpawnSkybox(int slot, string fogTargetName, string material)
7853
{
79-
if (prefab == null || prefab == "")
80-
{
81-
// directly spawn env_sky since prefab is empty so theres no need to create 3d skybox
82-
Utilities.FindAllEntitiesByDesignerName<CSkyCamera>("sky_camera").ToList().ForEach(camera => camera.Remove());
83-
var sky = Utilities.CreateEntityByName<CEnvSky>("env_sky")!;
84-
sky.PrivateVScripts = slot.ToString();
85-
sky.BrightnessScale = 1;
86-
sky.StartDisabled = false;
87-
sky.Enabled = true;
88-
sky.TintColor = Color.Transparent;
89-
sky.DispatchSpawn();
90-
if (SkyboxChanger.GetInstance().Config.Skyboxs.ContainsKey(""))
91-
{
92-
ChangeSkybox(slot, SkyboxChanger.GetInstance().Config.Skyboxs[""]);
93-
}
94-
return;
95-
}
96-
IntPtr ptr = Marshal.AllocHGlobal(0x30);
97-
for (int i = 0; i < 0x30; i++)
54+
var skycameras = Utilities.FindAllEntitiesByDesignerName<CSkyCamera>("sky_camera");
55+
uint spawngrouphandle = 0;
56+
if (skycameras.Count() != 0) // has 3d skybox
9857
{
99-
Marshal.WriteByte(ptr, i, 0);
100-
}
101-
CNetworkOriginCellCoordQuantizedVector vec = new(ptr);
102-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
103-
{
104-
SpawnPrefabEntities_Windows!.Invoke(0, 0, 0, ptr, KvLib.MakeKeyValue(prefab));
58+
var skycamera = skycameras.First();
59+
spawngrouphandle = *(uint*)(skycamera.Entity!.Handle + 0x34);
60+
MemoryManager.CreateLoadingSpawnGroupAndSpawnEntities(spawngrouphandle, true, true, KvLib.MakeKeyValue(fogTargetName, "skyboxchanger_" + slot, material));
10561
}
10662
else
10763
{
108-
// the param shit mismatch with ida
109-
SpawnPrefabEntities_Linux!.Invoke(0, 0, 0, 0, ptr, KvLib.MakeKeyValue(prefab), 0);
64+
var sky = Utilities.CreateEntityByName<CEnvSky>("env_sky");
65+
sky.PrivateVScripts = "skyboxchanger_" + slot;
66+
sky.DispatchSpawn();
67+
Server.NextFrame(() =>
68+
{
69+
ChangeSkybox(slot, null, 1f, Color.White);
70+
});
11071
}
11172
}
11273

113-
public static unsafe bool ChangeSkybox(int slot, Skybox skybox)
74+
public static unsafe bool ChangeSkybox(int slot, Skybox? skybox = null, float? brightness = null, Color? color = null)
11475
{
11576
// materialptr2 : CMaterial2** = InfoForResourceTypeIMaterial2
116-
var materialptr2 = FindMaterialByPath(skybox.Material);
117-
if (materialptr2 == 0)
118-
{
119-
return false;
120-
}
121-
Utilities.FindAllEntitiesByDesignerName<CEnvSky>("env_sky").ToList().ForEach(sky =>
77+
78+
79+
var sky = Utilities.GetEntityFromIndex<CEnvSky>(SkyboxChanger.GetInstance().EnvManager.SpawnedSkyboxes[slot])!;
80+
if (skybox != null)
12281
{
123-
if (slot == -1 || sky.PrivateVScripts == slot.ToString())
82+
var materialptr2 = FindMaterialByPath(skybox.Material);
83+
if (materialptr2 == 0)
12484
{
125-
Unsafe.Write((void*)sky.SkyMaterial.Handle, materialptr2);
126-
Unsafe.Write((void*)sky.SkyMaterialLightingOnly.Handle, materialptr2);
127-
Utilities.SetStateChanged(sky, "CEnvSky", "m_hSkyMaterial");
128-
Utilities.SetStateChanged(sky, "CEnvSky", "m_hSkyMaterialLightingOnly");
85+
return false;
12986
}
130-
});
87+
Unsafe.Write((void*)sky.SkyMaterial.Handle, materialptr2);
88+
Unsafe.Write((void*)sky.SkyMaterialLightingOnly.Handle, materialptr2);
89+
Utilities.SetStateChanged(sky, "CEnvSky", "m_hSkyMaterial");
90+
Utilities.SetStateChanged(sky, "CEnvSky", "m_hSkyMaterialLightingOnly");
91+
}
92+
93+
if (color != null)
94+
{
95+
sky.TintColor = (Color)color;
96+
}
97+
sky.BrightnessScale = brightness ?? skybox?.Brightness ?? sky.BrightnessScale;
98+
var colorData = skybox?.Color?.Split(" ");
99+
if (colorData != null && colorData.Length == 4)
100+
{
101+
var r = int.Parse(colorData[0]);
102+
var g = int.Parse(colorData[1]);
103+
var b = int.Parse(colorData[2]);
104+
var a = int.Parse(colorData[3]);
105+
sky.TintColor = Color.FromArgb(a, r, g, b);
106+
}
107+
Utilities.SetStateChanged(sky, "CEnvSky", "m_vTintColor");
108+
Utilities.SetStateChanged(sky, "CEnvSky", "m_flBrightnessScale");
131109
return true;
132110
}
133111

KvLib.cs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ public class KvLib
1313
public static extern void NativeInitialize(nint pGameEntitySystem);
1414

1515
[DllImport("kvlib", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
16-
public static extern nint NativeMakeKeyValue([MarshalAs(UnmanagedType.LPUTF8Str)] string targetMapName);
17-
18-
[DllImport("kvlib", CallingConvention = CallingConvention.Cdecl)]
19-
public static extern nint NativeGetTargetMapName(ulong pKeyValues);
16+
public static extern nint NativeMakeKeyValue([MarshalAs(UnmanagedType.LPUTF8Str)] string fogTargetName, [MarshalAs(UnmanagedType.LPUTF8Str)] string vscripts, [MarshalAs(UnmanagedType.LPUTF8Str)] string material);
2017

2118
public static bool Initialized { get; set; } = false;
2219

@@ -45,28 +42,14 @@ public static unsafe void Initialize()
4542
Initialized = true;
4643
}
4744

48-
public static nint MakeKeyValue(string targetMapName)
45+
public static nint MakeKeyValue(string fogTargetName, string vscripts, string material)
4946
{
5047
if (!Initialized)
5148
{
5249
Initialize();
5350
}
5451
// return 0;
55-
return NativeMakeKeyValue(targetMapName);
56-
}
57-
public static string? GetTargetMapName(nint pKeyValues)
58-
{
59-
if (!Initialized)
60-
{
61-
Initialize();
62-
}
63-
nint ptr = NativeGetTargetMapName((ulong)pKeyValues);
64-
if (ptr == 0)
65-
{
66-
return null;
67-
}
68-
string str = Marshal.PtrToStringUTF8(ptr)!;
69-
return str;
52+
return NativeMakeKeyValue(fogTargetName, vscripts, material);
7053
}
7154

7255

0 commit comments

Comments
 (0)