Skip to content

Commit a08d802

Browse files
committed
feat: random multiple default model
1 parent 9b93526 commit a08d802

9 files changed

Lines changed: 129 additions & 52 deletions

File tree

Cache.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void SetPlayerModel(ulong steamid, string modelIndex, Side side, bool per
7272
);
7373

7474
}
75+
7576
public ModelCache? GetPlayerModelCache(CCSPlayerController player)
7677
{
7778
return _Cache.Find(model => model.steamid == player!.AuthorizedSteamID!.SteamId64);

DefaultModelManager.cs

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using CounterStrikeSharp.API.Core;
22
using CounterStrikeSharp.API.Modules.Admin;
3-
using Newtonsoft.Json;
43
using Microsoft.Extensions.Logging;
4+
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Converters;
56

67
namespace PlayerModelChanger;
78

@@ -93,22 +94,75 @@ public DefaultModelEntry(EntryKey key, DefaultModel item, Side side)
9394
}
9495
}
9596

97+
public class DefaultModelIndexConverter : JsonConverter
98+
{
99+
public override bool CanConvert(Type objectType)
100+
{
101+
return objectType == typeof(List<string>) || objectType == typeof(string);
102+
}
103+
104+
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
105+
{
106+
if (reader.TokenType == JsonToken.String)
107+
{
108+
return new List<string> { (string)reader.Value! };
109+
}
110+
else if (reader.TokenType == JsonToken.StartArray)
111+
{
112+
var list = new List<string>();
113+
while (reader.Read())
114+
{
115+
if (reader.TokenType == JsonToken.EndArray)
116+
break;
117+
if (reader.TokenType == JsonToken.String)
118+
list.Add((string)reader.Value!);
119+
}
120+
return list;
121+
}
122+
123+
throw new JsonException("Expected string or array of strings");
124+
}
125+
126+
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
127+
{
128+
var list = (List<string>?)value;
129+
if (list == null) return;
130+
131+
writer.WriteStartArray();
132+
foreach (var item in list)
133+
{
134+
writer.WriteValue(item);
135+
}
136+
writer.WriteEndArray();
137+
}
138+
}
139+
96140
public class DefaultModel
97141
{
98-
public required string index;
99-
public bool force;
142+
[JsonProperty("index")]
143+
[JsonConverter(typeof(DefaultModelIndexConverter))]
144+
public required List<string> index;
145+
146+
[JsonProperty("force")]
147+
public bool force = false;
100148
}
101149

102150
class ConfigDefaultModelsTemplate
103151
{
104-
[JsonProperty("all")] public Dictionary<string, DefaultModel>? allModels = null;
105-
[JsonProperty("t")] public Dictionary<string, DefaultModel>? tModels = null;
106-
[JsonProperty("ct")] public Dictionary<string, DefaultModel>? ctModels = null;
152+
[JsonProperty("all")]
153+
public Dictionary<string, DefaultModel>? allModels = null;
107154

155+
[JsonProperty("t")]
156+
public Dictionary<string, DefaultModel>? tModels = null;
157+
158+
[JsonProperty("ct")]
159+
public Dictionary<string, DefaultModel>? ctModels = null;
108160
}
161+
109162
class ConfigTemplate
110163
{
111-
[JsonProperty("DefaultModels")] public required ConfigDefaultModelsTemplate models { get; set; }
164+
[JsonProperty("DefaultModels")]
165+
public required ConfigDefaultModelsTemplate models { get; set; }
112166
}
113167

114168
public class DefaultModelManager
@@ -122,8 +176,7 @@ public void ReloadConfig(string ModuleDirectory, ModelService service)
122176
var filePath = Path.Join(ModuleDirectory, "../../configs/plugins/PlayerModelChanger/DefaultModels.json");
123177
if (File.Exists(filePath))
124178
{
125-
StreamReader reader = File.OpenText(filePath);
126-
string content = reader.ReadToEnd();
179+
string content = File.ReadAllText(filePath);
127180
ConfigTemplate config = JsonConvert.DeserializeObject<ConfigTemplate>(content)!;
128181

129182
DefaultModels = ParseModelConfig(config.models, service);
@@ -188,11 +241,14 @@ private static List<DefaultModelEntry> ParseModelConfig(ConfigDefaultModelsTempl
188241
}
189242
for (var i = 0; i < defaultModels.Count; i++)
190243
{
191-
192-
if (service.GetModel(defaultModels[i].item.index) == null)
244+
foreach (var index in defaultModels[i].item.index)
193245
{
194-
PlayerModelChanger.getInstance().Logger.LogInformation($"model '${defaultModels[i].item.index}' defined in DefaultModels.json does not exist. Skipped.");
195-
defaultModels.RemoveAt(i);
246+
if (index != "" || service.GetModel(index) == null)
247+
{
248+
PlayerModelChanger.getInstance().Logger.LogInformation($"model '${index}' defined in DefaultModels.json does not exist. Skipped.");
249+
defaultModels.RemoveAt(i);
250+
break;
251+
}
196252
}
197253
}
198254
return defaultModels;
@@ -226,7 +282,7 @@ private static List<DefaultModelEntry> ParseModelConfig(ConfigDefaultModelsTempl
226282
{
227283
return null;
228284
}
229-
if (result.item == null || result.item.index == "")
285+
if (result.item == null || result.item.index.Count == 0)
230286
{
231287
return null;
232288
}

Model.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class Model
1414
[JsonConverter(typeof(CaseInsensitiveJsonStringEnumConverter))]
1515
public Side Side { get; set; } = Side.All;
1616
[JsonPropertyName("disableleg")] public bool Disableleg { get; set; }
17-
[JsonPropertyName("hideinmenu")] public bool Hideinmenu { get; set; }
17+
[JsonPropertyName("hideinmenu")] public bool HideInMenu { get; set; }
1818
[JsonPropertyName("fixedmeshgroups")] public Dictionary<int, int> FixedMeshgroups { get; set; } = [];
1919
[JsonPropertyName("meshgroups")] public Dictionary<string, dynamic> Meshgroups { get; set; } = new();
2020
}

PlayerModelChanger.cs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
using System.Drawing;
77
using CounterStrikeSharp.API.Modules.Config;
88
using Microsoft.Extensions.Logging;
9+
using CounterStrikeSharp.API.Modules.Memory;
10+
using System.Runtime.InteropServices;
911
namespace PlayerModelChanger;
1012

1113
public partial class PlayerModelChanger : BasePlugin, IPluginConfig<ModelConfig>
1214
{
1315
public override string ModuleName => "Player Model Changer";
14-
public override string ModuleVersion => "1.8.2";
16+
public override string ModuleVersion => "1.8.3";
1517

1618
public override string ModuleAuthor => "samyyc";
1719
public required ModelConfig Config { get; set; }
@@ -100,8 +102,6 @@ public override void Unload(bool hotReload)
100102
RemoveListener<Listeners.OnTick>(OnTick);
101103
DeregisterEventHandler<EventPlayerSpawn>(OnPlayerSpawnEvent);
102104
Logger.LogInformation("Unloaded successfully.");
103-
104-
105105
}
106106

107107
public static PlayerModelChanger getInstance()
@@ -265,24 +265,27 @@ public HookResult OnPlayerSpawnEvent(EventPlayerSpawn @event, GameEventInfo info
265265
}
266266
}
267267

268-
Server.NextFrame(() =>
268+
AddTimer(0.03f, () =>
269269
{
270-
if (!Service.MapDefaultModelInitialized(player))
271-
{
272-
Service.SetMapDefaultModel(player, player.PlayerPawn.Value.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName);
273-
}
274270
Server.NextFrame(() =>
275271
{
276-
var model = Service.GetPlayerNowTeamModel(player);
277-
if (model != null)
272+
if (!Service.MapDefaultModelInitialized(player))
278273
{
279-
SetModelNextServerFrame(player, model, model.Disableleg);
274+
Service.SetMapDefaultModel(player, player.PlayerPawn.Value.CBodyComponent!.SceneNode!.GetSkeletonInstance().ModelState.ModelName);
280275
}
281-
else
276+
Server.NextFrame(() =>
282277
{
283-
var originalRender = player.PlayerPawn.Value.Render;
284-
player.PlayerPawn.Value.Render = Color.FromArgb(255, originalRender.R, originalRender.G, originalRender.B);
285-
}
278+
var model = Service.GetPlayerNowTeamModel(player);
279+
if (model != null)
280+
{
281+
SetModelNextServerFrame(player, model, model.Disableleg);
282+
}
283+
else
284+
{
285+
var originalRender = player.PlayerPawn.Value.Render;
286+
player.PlayerPawn.Value.Render = Color.FromArgb(255, originalRender.R, originalRender.G, originalRender.B);
287+
}
288+
});
286289
});
287290
});
288291
}

Service.cs

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ public static void InitializeModel(string key, Model model)
4848
model.Name = model.Index;
4949
}
5050
}
51-
5251
public void ReloadConfig(string ModuleDirectory, ModelConfig config)
5352
{
5453
this._Config = config;
@@ -125,6 +124,7 @@ public void SetPlayerAllModel(ulong steamid, string? tModel, string? ctModel, bo
125124
}
126125
}
127126
}
127+
128128
public void SetPlayerModel(ulong steamid, string? modelIndex, CsTeam team, bool permissionBypass)
129129
{
130130
var side = team == CsTeam.Terrorist ? Side.T : Side.CT;
@@ -157,24 +157,24 @@ public Tuple<bool, bool> CheckAndReplaceModel(CCSPlayerController player)
157157
var defaultCTModel = _DefaultModelManager.GetPlayerDefaultModel(player, Side.CT);
158158
if (modelCache == null) // player first time join
159159
{
160-
SetPlayerAllModel(steamid, defaultTModel?.index, defaultCTModel?.index, false, false);
160+
SetPlayerAllModel(steamid, "@default", "@default", false, false);
161161
return new Tuple<bool, bool>(false, false);
162162
}
163163
var tValid = CheckModel(player, Side.T, modelCache, defaultTModel);
164164
var ctValid = CheckModel(player, Side.CT, modelCache, defaultCTModel);
165165
if (!tValid && !ctValid)
166166
{
167-
SetPlayerAllModel(steamid, defaultTModel?.index, defaultCTModel?.index, false);
167+
SetPlayerAllModel(steamid, "@default", "@default", false);
168168
return new Tuple<bool, bool>(true, true);
169169
}
170170
else if (!tValid)
171171
{
172-
SetPlayerModel(steamid, defaultTModel?.index, Side.T, false);
172+
SetPlayerModel(steamid, "@default", Side.T, false);
173173
return new Tuple<bool, bool>(true, false);
174174
}
175175
else if (!ctValid)
176176
{
177-
SetPlayerModel(steamid, defaultCTModel?.index, Side.CT, false);
177+
SetPlayerModel(steamid, "@default", Side.CT, false);
178178
return new Tuple<bool, bool>(false, true);
179179
}
180180
return new Tuple<bool, bool>(false, false);
@@ -192,18 +192,15 @@ public bool CheckModel(CCSPlayerController player, Side side, ModelCache? modelC
192192
{
193193
return true;
194194
}
195-
if (defaultModel != null && defaultModel.force)
195+
if (defaultModel != null && defaultModel.force && modelIndex != "@default")
196196
{
197-
if (modelIndex != defaultModel.index)
198-
{
199-
return false;
200-
}
197+
return false;
201198
}
202199
if (modelIndex == "@random" && _Config.DisableRandomModel)
203200
{
204201
return false;
205202
}
206-
if (modelIndex == "" || modelIndex == "@random")
203+
if (modelIndex == "" || modelIndex == "@random" || modelIndex == "@default")
207204
{
208205
return true;
209206
}
@@ -216,28 +213,35 @@ public bool CheckModel(CCSPlayerController player, Side side, ModelCache? modelC
216213
return CanPlayerApplyModel(player, side, model);
217214
}
218215

219-
public bool SetPlayerModelWithCheck(CCSPlayerController player, string modelIndex, Side side)
216+
private bool IsPlayerInCooldown(CCSPlayerController player)
220217
{
221218
if (_ModelChangeCooldown.ContainsKey(player.SteamID))
222219
{
223220
var lastTime = _ModelChangeCooldown[player.SteamID];
224221
if (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - lastTime < (_Config.ModelChangeCooldownSecond * 1000))
225222
{
226223
player.PrintToChat(_Localizer["command.model.cooldown"]);
227-
return false;
224+
return true;
228225
}
229226
}
227+
return false;
228+
}
229+
230+
public bool SetPlayerModelWithCheck(CCSPlayerController player, string modelIndex, Side side)
231+
{
232+
if (IsPlayerInCooldown(player))
233+
{
234+
return false;
235+
}
230236

231237
var isSpecial = modelIndex == "" || modelIndex == "@random";
232238

233239
if (modelIndex == "@default")
234240
{
235-
var tDefault = _DefaultModelManager.GetPlayerDefaultModel(player, Side.T);
236-
var ctDefault = _DefaultModelManager.GetPlayerDefaultModel(player, Side.CT);
237241
Utils.ExecuteSide(side,
238-
() => SetPlayerAllModel(player!.AuthorizedSteamID!.SteamId64, tDefault == null ? "" : tDefault.index, ctDefault == null ? "" : ctDefault.index, false),
239-
() => SetPlayerModel(player!.AuthorizedSteamID!.SteamId64, tDefault == null ? "" : tDefault.index, side, false),
240-
() => SetPlayerModel(player!.AuthorizedSteamID!.SteamId64, ctDefault == null ? "" : ctDefault.index, side, false)
242+
() => SetPlayerAllModel(player!.AuthorizedSteamID!.SteamId64, "@default", "@default", false),
243+
() => SetPlayerModel(player!.AuthorizedSteamID!.SteamId64, "@default", side, false),
244+
() => SetPlayerModel(player!.AuthorizedSteamID!.SteamId64, "@default", side, false)
241245
);
242246
if (_Config.DisableInstantChange || !Utils.CanPlayerSetModelInstantly(player, side))
243247
{
@@ -277,8 +281,8 @@ public bool SetPlayerModelWithCheck(CCSPlayerController player, string modelInde
277281
player.PrintToChat(_Localizer["command.model.success", _Localizer["side." + side.ToName()]]);
278282
}
279283
return true;
280-
281284
}
285+
282286
public Model? GetPlayerModel(CCSPlayerController player, Side side)
283287
{
284288
if (side == Side.All)
@@ -303,6 +307,20 @@ public bool SetPlayerModelWithCheck(CCSPlayerController player, string modelInde
303307
var index = Random.Shared.Next(models.Count());
304308
return models[index];
305309
}
310+
if (modelIndex == "@default")
311+
{
312+
var defaultModel = _DefaultModelManager.GetPlayerDefaultModel(player, side);
313+
if (defaultModel == null || defaultModel.index.Count == 0)
314+
{
315+
return null;
316+
}
317+
var index = defaultModel.index[Random.Shared.Next(defaultModel.index.Count)];
318+
if (index == "")
319+
{
320+
return null;
321+
}
322+
return GetModel(index);
323+
}
306324
return GetModel(modelIndex);
307325
}
308326

@@ -316,6 +334,7 @@ public bool SetPlayerModelWithCheck(CCSPlayerController player, string modelInde
316334
var side = team == CsTeam.Terrorist ? Side.T : Side.CT;
317335
return GetPlayerModel(player, side);
318336
}
337+
319338
public string GetPlayerModelName(CCSPlayerController player, CsTeam team)
320339
{
321340
var modelCache = _CacheManager.GetPlayerModelCache(player);
@@ -457,5 +476,4 @@ public void ClearMapDefaultModel()
457476
{
458477
_MapDefaultModels.Clear();
459478
}
460-
461479
}

Storage.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public interface IStorage
88
public void SetPlayerCTModel(ulong SteamID, string modelIndex, bool permissionBypass);
99
public void SetAllTModel(string tmodel, bool permissionBypass);
1010
public void SetAllCTModel(string ctmodel, bool permissionBypass);
11-
1211
public List<int> GetMeshgroupPreference(ulong SteamID, string modelIndex);
1312
public void AddMeshgroupPreference(ulong SteamID, string modelIndex, int meshgroup);
1413
public void RemoveMeshgroupPreference(ulong SteamID, string modelIndex, int meshgroup);
1 KB
Binary file not shown.
676 Bytes
Binary file not shown.

commands/CommandModelMenu.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public WasdModelMenu GetSelectModelMenu(CCSPlayerController player, Side side)
6565

6666
foreach (var model in models)
6767
{
68-
if (model.Hideinmenu)
68+
if (model.HideInMenu)
6969
{
7070
continue;
7171
}

0 commit comments

Comments
 (0)