From 83de57ff19cd54b00c57415a5412647debcd653d Mon Sep 17 00:00:00 2001 From: Artem Dzhemesiuk Date: Mon, 25 Sep 2023 01:21:33 +0200 Subject: [PATCH] Numerous bugfixes and improvements to freeroam-extended gamemode --- freeroam-extended/client/html/app.js | 2 +- freeroam-extended/client/html/index.html | 6 +- freeroam-extended/client/html/style.css | 27 +- freeroam-extended/client/package.json | 6 +- freeroam-extended/client/src/chat.ts | 5 +- freeroam-extended/client/src/events.ts | 18 +- freeroam-extended/client/src/helpers.ts | 17 +- freeroam-extended/client/yarn.lock | 24 +- .../server/freeroam-extended/AdminCommands.cs | 498 +++++++++++++++++ .../server/freeroam-extended/Commands.cs | 500 ++---------------- .../Constants/ChatConstants.cs | 10 + .../Constants/VehicleConstants.cs | 144 +++++ .../Controllers/AppearanceController.cs | 120 +++++ .../Controllers/ChatController.cs | 62 +++ .../Controllers/PlayerController.cs | 105 ++++ .../Controllers/StatsController.cs | 79 +++ .../Controllers/VehicleController.cs | 148 ++++++ .../Controllers/VoiceController.cs | 64 +++ .../server/freeroam-extended/EventHandler.cs | 168 +++--- .../Factories/PlayerFactory.cs | 148 ++---- .../Freeroam-Extended.csproj | 5 +- .../server/freeroam-extended/Main.cs | 72 +-- .../server/freeroam-extended/Misc.cs | 154 +----- .../server/freeroam-extended/StatsHandler.cs | 26 - .../server/freeroam-extended/Voice.cs | 54 -- 25 files changed, 1451 insertions(+), 1011 deletions(-) create mode 100644 freeroam-extended/server/freeroam-extended/AdminCommands.cs create mode 100644 freeroam-extended/server/freeroam-extended/Constants/ChatConstants.cs create mode 100644 freeroam-extended/server/freeroam-extended/Constants/VehicleConstants.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/AppearanceController.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/ChatController.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/PlayerController.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/StatsController.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/VehicleController.cs create mode 100644 freeroam-extended/server/freeroam-extended/Controllers/VoiceController.cs delete mode 100644 freeroam-extended/server/freeroam-extended/StatsHandler.cs delete mode 100644 freeroam-extended/server/freeroam-extended/Voice.cs diff --git a/freeroam-extended/client/html/app.js b/freeroam-extended/client/html/app.js index c27ab3a..04f622e 100644 --- a/freeroam-extended/client/html/app.js +++ b/freeroam-extended/client/html/app.js @@ -236,7 +236,7 @@ function setVoiceConnectionState(state) { } alt.on("addString", (text) => addString(colorify(text))); -alt.on("addMessage", (name, text) => addString("" + name + ": " + colorify(text))); +alt.on("addMessage", (name, text) => addString("" + colorify(name) + ": " + colorify(text))); alt.on("openChat", openChat); alt.on("closeChat", closeChat); alt.on("updatePlayersOnline", updatePlayersOnline); diff --git a/freeroam-extended/client/html/index.html b/freeroam-extended/client/html/index.html index 055ed53..91e4ec6 100644 --- a/freeroam-extended/client/html/index.html +++ b/freeroam-extended/client/html/index.html @@ -9,7 +9,9 @@
- Public Stress Test - v15 +
+ Public Stress Test - v15 +
@@ -38,7 +40,7 @@
  • /tp <1 to 22> (Teleport)
  • /model (Change your model between male and female)
  • -
  • /outfit [outfit_name] (Change outfit to random or entered value)
  • +
  • /outfit <outfitName> (Change outfit to random or entered value)
  • /veh <modelName> (Spawn a vehicle)
  • /clearvehicles (Clear your vehicles)
  • /tune <index> <value> (Tune vehicle)
  • diff --git a/freeroam-extended/client/html/style.css b/freeroam-extended/client/html/style.css index 009d879..9ded38c 100644 --- a/freeroam-extended/client/html/style.css +++ b/freeroam-extended/client/html/style.css @@ -256,14 +256,7 @@ body { } .stress-test-label { - top: .2em; - left: 50%; - transform: translateX(-50%); - text-align: center; - width: 100%; - font-size: .8em; - position: absolute; - color: rgba(255, 255, 255, 0.628); + font-size: 16px; } .weapons-enabled > * { @@ -307,3 +300,21 @@ body { .streamed-in > * { } + +.watermark { + pointer-events: none; + position: fixed; + color: rgba(255, 255, 255, 0.75); + font-weight: 500; + padding: 1em; + font-size: 0.9em; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + z-index: 201; + opacity: 1; + + font-family: 'Inter'; + top: 0; + left: 50%; + transform: translateX(-50%); + text-align: center; +} \ No newline at end of file diff --git a/freeroam-extended/client/package.json b/freeroam-extended/client/package.json index ac8adef..f632b2f 100644 --- a/freeroam-extended/client/package.json +++ b/freeroam-extended/client/package.json @@ -4,10 +4,10 @@ "main": "index.js", "license": "MIT", "devDependencies": { - "@altv/types-client": "^2.9.2", + "@altv/types-client": "^2.9.7", "@altv/types-natives": "^1.5.4", - "@altv/types-server": "^2.9.5", - "@altv/types-shared": "^1.6.0", + "@altv/types-server": "^3.0.1", + "@altv/types-shared": "^1.6.5", "@typescript-eslint/eslint-plugin": "^5.50.0", "@typescript-eslint/parser": "^5.50.0", "altv-esbuild": "^0.4.3", diff --git a/freeroam-extended/client/src/chat.ts b/freeroam-extended/client/src/chat.ts index b01a353..63d5438 100644 --- a/freeroam-extended/client/src/chat.ts +++ b/freeroam-extended/client/src/chat.ts @@ -53,8 +53,7 @@ view.on("chatloaded", () => { }) view.on("chatmessage", (text: string) => { - if (playerData.chatState) - alt.emitServer("chat:message", text) + alt.emitServer("chat:message", text) alt.toggleGameControls(true) view.unfocus() @@ -65,4 +64,4 @@ view.on("chatmessage", (text: string) => { }, 200) }) -pushLine("alt:V Multiplayer has started") +pushLine("alt:V Multiplayer has started") diff --git a/freeroam-extended/client/src/events.ts b/freeroam-extended/client/src/events.ts index 55803f0..8f5aba6 100644 --- a/freeroam-extended/client/src/events.ts +++ b/freeroam-extended/client/src/events.ts @@ -16,23 +16,23 @@ alt.on("connectionComplete", () => { }, 1000) }) +alt.on("localMetaChange", (key: string, newValue: any) => { + if (key == "godmode") + native.setEntityInvincible(alt.Player.local, newValue); +}) + alt.onServer("airport_state", setWeaponsUsage) alt.onServer("chat:message", chat.pushMessage) alt.onServer("noclip", toggleNoclip) -alt.onServer("set_chat_state", (state: boolean) => { - playerData.chatState = state -}) - alt.onServer("draw_dmzone", ( centerX: number, centerY: number, - radius: number, - count: number, + radius: number ) => { - drawDMZone(centerX, centerY, radius, count) + drawDMZone(centerX, centerY, radius) }) alt.onServer("announce", (header: string, body: string, time: number) => { @@ -84,9 +84,9 @@ alt.on("keyup", (key) => { }) alt.onServer("get_pos", () => { - const state = alt.getPermissionState(Permission.ClipboardAccess) + const state = alt.getPermissionState(Permission.CLIPBOARD_ACCESS) - if (state !== PermissionState.Allowed) { + if (state !== PermissionState.ALLOWED) { alt.log("get_pos clipboard access is not allowed, state:", state) return } diff --git a/freeroam-extended/client/src/helpers.ts b/freeroam-extended/client/src/helpers.ts index 88874cc..10ab0b0 100644 --- a/freeroam-extended/client/src/helpers.ts +++ b/freeroam-extended/client/src/helpers.ts @@ -132,18 +132,13 @@ export function drawDMZone( centerX: number, centerY: number, radius: number, - count: number, ): void { - const steps = 2 * Math.PI / count - for (let i = 0; i < count; i++) { - const blipX = radius * Math.cos(steps * i) + centerX - const blipY = radius * Math.sin(steps * i) + centerY - - const blip = new alt.PointBlip(blipX, blipY, 0) - blip.sprite = 310 - blip.shortRange = true - native.setBlipHiddenOnLegend(blip.scriptID, true) - } + const blip = new alt.RadiusBlip(centerX, centerY, 0, radius); + blip.sprite = 10; + blip.shortRange = true; + blip.color = 5; + blip.isHiddenOnLegend = false; + blip.name = "DM zone"; } let adminMessageEveryTick: number | null = null diff --git a/freeroam-extended/client/yarn.lock b/freeroam-extended/client/yarn.lock index db15c2a..cd6d369 100644 --- a/freeroam-extended/client/yarn.lock +++ b/freeroam-extended/client/yarn.lock @@ -2,25 +2,25 @@ # yarn lockfile v1 -"@altv/types-client@^2.9.2": - version "2.9.2" - resolved "https://registry.npmjs.org/@altv/types-client/-/types-client-2.9.2.tgz" - integrity sha512-LMGD1EBebN6BjFohhvPijR1Rq8BnU24IGdPb2It7NGFhHXxX/688XnlfX+tquIKlUkQPR8D54imNzZKBUG+BWA== +"@altv/types-client@^2.9.7": + version "2.9.7" + resolved "https://registry.yarnpkg.com/@altv/types-client/-/types-client-2.9.7.tgz#9082db1af8dbd7f04bc5f33e8ad67adcf6d9afba" + integrity sha512-VCuo56pzGLJedu6oiesAoKtFc7O5ZhAHH7W/WOX1dGU+PXWIM0B6OYbYuIOr6AOLwTCVTv+QpUrKgkN+38WCyA== "@altv/types-natives@^1.5.4": version "1.5.4" resolved "https://registry.npmjs.org/@altv/types-natives/-/types-natives-1.5.4.tgz" integrity sha512-N4jtJ4f8KFOCi0sxlVvTWF7I7Nz/ylq136sIJMpsHIcBWIlysWF6zdJFdBW5bkquDGWgY8aBYPQ4TU+ayQhukw== -"@altv/types-server@^2.9.5": - version "2.9.5" - resolved "https://registry.npmjs.org/@altv/types-server/-/types-server-2.9.5.tgz" - integrity sha512-Io4UkkJcbo9e6XqQd/dtQyQfOucko+vYmivQPJC/WemCCrQuMBWd4teqW3AUxcpT81psOnnJkHEVxfth386zmw== +"@altv/types-server@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@altv/types-server/-/types-server-3.0.1.tgz#83b41032cab2522cc62ffc6441c5fef08440229e" + integrity sha512-dVEGQUCj/IiFAw2oC1jQ3Iiacqtk5ciA2BNXJIETFcY2tz0uVaNMFAszR4B4xNBctWnXY12RDCJRrrvcxrPTMg== -"@altv/types-shared@^1.6.0": - version "1.6.0" - resolved "https://registry.npmjs.org/@altv/types-shared/-/types-shared-1.6.0.tgz" - integrity sha512-OURm829uVVxKFMPtWx/ZUR9K7cw7ZISCt5qdFzRO0MUdd+HAX3hymJqyy3euksTkxlBpGQXox432I0Sk02aurg== +"@altv/types-shared@^1.6.5": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@altv/types-shared/-/types-shared-1.6.5.tgz#f3cd941a2706065e284cd0b053936fc0d0856024" + integrity sha512-gOil0Is/T26XCAJ+96H3qEjq7zLc9sG7vGp14UVZD09Vn0ClxUx3EG1xapJcobUuJHUd1uI24j1ODSzZ/pSMtA== "@esbuild/linux-loong64@0.14.53": version "0.14.53" diff --git a/freeroam-extended/server/freeroam-extended/AdminCommands.cs b/freeroam-extended/server/freeroam-extended/AdminCommands.cs new file mode 100644 index 0000000..1d447a0 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/AdminCommands.cs @@ -0,0 +1,498 @@ +using System.Numerics; +using System.Text.Json; +using AltV.Net; +using AltV.Net.Async; +using AltV.Net.Data; +using AltV.Net.Elements.Entities; +using AltV.Net.Enums; +using AltV.Net.Resources.Chat.Api; +using Freeroam_Extended.Clothes; +using Freeroam_Extended.Factories; + +namespace Freeroam_Extended +{ + public class AdminCommands : IScript + { + private void SendVehListHelp(IAltPlayer player) + { + player.SendChatMessage("/vehlist mode [blacklist,whitelist] - change vehicle list mode"); + player.SendChatMessage("/vehlist allow [vehicle model] - allow vehicle (add to whitelist or remove from blacklist)"); + player.SendChatMessage("/vehlist block [vehicle model] - block vehicle (add to blacklist or remove from whitelist)"); + player.SendChatMessage("/vehlist clear - remove all vehicles from list"); + player.SendChatMessage("/vehlist status - show status and vehicle list"); + } + + [Command("vehlist")] + public void VehList(IAltPlayer player, params string[] args) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (args.Length < 1) + { + SendVehListHelp(player); + return; + } + + switch (args[0]) + { + case "mode" when args.Length > 1 && args[1] == "blacklist": + VehicleController.UpdateState(false); + ChatController.BroadcastAdmins($"Vehicle list was changed to blacklist by {player.Serialize()}"); + break; + + case "mode" when args.Length > 1 && args[1] == "whitelist": + VehicleController.UpdateState(true); + ChatController.BroadcastAdmins($"Vehicle list was changed to whitelist by {player.Serialize()}"); + break; + + case "allow" when args.Length > 1: + if (!Enum.IsDefined(typeof(VehicleModel), Alt.Hash(args[1]))) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Invalid vehicle model!"); + return; + } + VehicleController.Allow(args[1]); + ChatController.BroadcastAdmins($"Vehicle {args[1]} was {(VehicleController.IsWhitelist ? "added to whitelist" : "removed from blacklist")} by {player.Serialize()}"); + break; + + case "block" when args.Length > 1: + if (!Enum.IsDefined(typeof(VehicleModel), Alt.Hash(args[1]))) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Invalid vehicle model!"); + return; + } + VehicleController.Block(args[1]); + ChatController.BroadcastAdmins($"Vehicle {args[1]} was {(VehicleController.IsWhitelist ? "removed from whitelist" : "added to blacklist")} by {player.Serialize()}"); + break; + + case "clear": + VehicleController.Clear(); + ChatController.BroadcastAdmins($"Vehicle list was cleared by {player.Serialize()}"); + break; + + case "list": + player.SendChatMessage($"{(VehicleController.IsWhitelist ? "Whitelisted" : "Blacklisted")} vehicles: {string.Join(", ", VehicleController.List)}"); + break; + + default: + SendVehListHelp(player); + break; + } + } + + #region Punishments + [Command("ban")] + public void Ban(IAltPlayer player, int id) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (player.Id == id) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "You can't ban yourself!"); + return; + } + + if (Alt.GetPlayerById((uint) id) is not IAltPlayer target) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + $"Player with id {id} not found!"); + return; + } + + var name = target.Serialize(); + PlayerController.Ban(target); + ChatController.BroadcastAdmins($"Player {name} was banned by {player.Serialize()}!"); + } + + [Command("kick")] + public void Kick(IAltPlayer player, int id) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (player.Id == id) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "You can't kick yourself!"); + return; + } + + var target = (IAltPlayer) Alt.GetPlayerById((uint) id); + if (target == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + $"Player with id {id} not found!"); + return; + } + + var name = target.Serialize(); + target.Kick("You've been kicked from this server!"); + + ChatController.BroadcastAdmins($"Player {name} was kicked by {player.Serialize()}!"); + } + + [Command("mutelist")] + public void Mutelist(IAltPlayer player) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var found = new HashSet(); + var muted = new List(); + foreach (var p in Alt.GetAllPlayers()) + { + if (p is not IAltPlayer target || !target.Data.Muted) continue; + muted.Add(target.CloudID + " - " + target.Serialize()); + found.Add(target.CloudID); + } + + foreach (var (key, value) in PlayerController.PlayerData) + { + if (!value.Muted) continue; + if (found.Contains(key)) continue; + muted.Add(key + " - Offline"); + } + + player.SendChatMessage("Muted players: " + string.Join(", ", muted)); + } + + [Command("mute")] + public void Mute(IAltPlayer player, int id) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (player.Id == id) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "You can't mute yourself!"); + return; + } + + var target = (IAltPlayer) Alt.GetPlayerById((uint) id); + if (target == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + $"Player with id {id} not found!"); + return; + } + PlayerController.Mute(target, player); + } + + [Command("unmute")] + public void Unmute(IAltPlayer player, int id) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var target = (IAltPlayer) Alt.GetPlayerById((uint) id); + if (target == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + $"Player with id {id} not found!"); + return; + } + PlayerController.Unmute(target, player); + } + #endregion + + #region Teleports + [Command("dimension")] + public void Dimension(IAltPlayer player, int dimension = 0) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + player.Dimension = dimension; + } + + [Command("tpallhere")] + public void TpAllHere(IAltPlayer player) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + foreach (var p in Alt.GetAllPlayers()) + { + if (p is not IAltPlayer target || p.Id == player.Id || target.IsAdmin) continue; + target.Position = player.Position; + target.SendChatMessage(ChatConstants.SuccessPrefix + "You were teleported to " + player.Serialize() + "!"); + } + } + + [Command("tphere")] + public void TpHere(IAltPlayer player, int target) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var targetPlayer = (IAltPlayer)Alt.GetPlayerById((uint) target); + if (targetPlayer == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Player not found!"); + return; + } + + targetPlayer.Position = player.Position; + targetPlayer.SendChatMessage(ChatConstants.SuccessPrefix + "You were teleported to " + player.Serialize() + "!"); + } + + [Command("tpto")] + public void TpTo(IAltPlayer player, int target) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var targetPlayer = (IAltPlayer)Alt.GetPlayerById((uint) target); + if (targetPlayer == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Player not found!"); + return; + } + + player.Position = targetPlayer.Position; + player.SendChatMessage(ChatConstants.SuccessPrefix + "You were teleported to " + targetPlayer.Serialize() + "!"); + } + + [Command("tpcoords")] + public void TpCoords(IAltPlayer player, int x, int y, int z) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + player.Position = new Vector3(x, y, z); + player.SendChatMessage(ChatConstants.SuccessPrefix + $"You were teleported to {x}, {y}, {z}!"); + } + #endregion + + #region World state + [Command("settime")] + public void SetTime(IAltPlayer player, int hour) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (hour > 23 || hour < 0) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Invalid hour!"); + return; + } + + foreach (var p in Alt.GetAllPlayers()) + { + p.SetDateTime(0, 0, 0, hour, 0, 0); + } + + ChatController.BroadcastAdmins($"{player.Serialize()} set time to {hour}"); + } + + [Command("togglechat")] + public void ToggleChat(IAltPlayer player) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + ChatController.ChatState = !ChatController.ChatState; + player.SendChatMessage(ChatConstants.SuccessPrefix + "Chat is now " + (ChatController.ChatState ? "enabled" : "disabled") + "!"); + } + + [Command("overridespawnpos")] + public void OverrideSpawnPos(IAltPlayer player, bool mode) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (mode) + { + var pos = player.Position; + Misc.AdminOverridedSpawnPos = pos; + + player.SendChatMessage( + ChatConstants.SuccessPrefix + $"You overrode spawn position for all players on {pos.X}, {pos.Y}, {pos.Z}!"); + } + else + { + Misc.AdminOverridedSpawnPos = null; + player.SendChatMessage(ChatConstants.ErrorPrefix + $"You reset overridden spawn position!"); + } + } + + [Command("godmodeall")] + public void GodmodeAllPlayers(IAltPlayer player, bool mode) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var targets = Alt.GetAllPlayers().ToList(); + + foreach (var target in targets) + { + target.SetLocalMetaData("godmode", mode); + target.SendChatMessage(ChatConstants.SuccessPrefix + $"Godmode for all players is {(mode ? "activated" : "deactivated")}!"); + } + } + #endregion + + #region Local state + [Command("noclip")] + public void NoClip(IAltPlayer player) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + player.NoClip = !player.NoClip; + player.Streamed = !player.NoClip; + player.Visible = !player.NoClip; + player.SendChatMessage(ChatConstants.SuccessPrefix + $"NoClip is now {(player.NoClip ? "enabled" : "disabled")}!"); + + player.Emit("noclip", player.NoClip); + } + + [Command("godmode")] + public void Godmode(IAltPlayer player, int id = 0) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var target = id == 0 ? player : Alt.GetPlayerById((uint) id); + if (target == null) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + $"Player with id {id} not found!"); + return; + } + + var hadValue = target.GetLocalMetaData("godmode", out bool prevValue); + var newValue = !hadValue || !prevValue; + target.SetLocalMetaData("godmode", newValue); + target.Invincible = !target.Invincible; + var msg = ChatConstants.SuccessPrefix + $"Godmode {(newValue ? "on" : "off")}!"; + target.SendChatMessage(msg); + + if (player.Id != target.Id) + player.SendChatMessage(msg); + } + + // [Command("esp")] + // public void Esp(IAltPlayer player, bool mode) + // { + // if (!player.IsAdmin) + // { + // player.SendChatMessage(ChatConstants.NoPermissions); + // return; + // } + // + // player.Emit("esp", mode); + // } + + [Command("globalvoice")] + public void GlobalVoice(IAltPlayer player) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + if (VoiceController.IsGlobalVoiceEnabled(player)) + { + VoiceController.EnableGlobalVoice(player); + player.SendChatMessage(ChatConstants.SuccessPrefix + "Global voice enabled!"); + return; + } + else + { + VoiceController.DisableGlobalVoice(player); + player.SendChatMessage(ChatConstants.ErrorPrefix + "Global voice disabled!"); + return; + } + } + #endregion + + #region Actions + [Command("announce")] + public void Announce(IAltPlayer player, string header, int time, params string[] body) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var message = string.Join(" ", body); + Alt.EmitAllClients("announce", header.Replace("_", " "), message, time); + } + + [Command("clearallvehicles")] + public void ClearAllVehicles(IAltPlayer player, int distance = 0) + { + if (!player.IsAdmin) + { + player.SendChatMessage(ChatConstants.NoPermissions); + return; + } + + var distSqr = distance * distance; + foreach (var altVehicle in Alt.GetAllVehicles()) + { + var veh = (IAltVehicle) altVehicle; + if (distance == 0 || Vector3.DistanceSquared(veh.Position, player.Position) <= distSqr) + { + if (veh.Owner is { Exists: true }) + { + veh.Owner.SendChatMessage(ChatConstants.ErrorPrefix + "Your vehicle was removed!"); + } + + veh.Destroy(); + } + } + } + #endregion + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Commands.cs b/freeroam-extended/server/freeroam-extended/Commands.cs index bf828a2..894976f 100644 --- a/freeroam-extended/server/freeroam-extended/Commands.cs +++ b/freeroam-extended/server/freeroam-extended/Commands.cs @@ -13,37 +13,52 @@ namespace Freeroam_Extended public class Commands : IScript { private readonly Random _random = new(); - + [Command("veh")] - public void SpawnVeh(IAltPlayer player, string vehicleName) + public void SpawnVeh(IAltPlayer player, params string[] args) { - if (Misc.BlacklistedVehicle.Contains(Alt.Hash(vehicleName)) && !player.IsAdmin) + if (args.Length < 1) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Usage: /veh [vehicle name]"); + return; + } + + var vehicleName = args[0]; + + if (player.EnableWeaponUsage) { - player.SendChatMessage("{FF0000} Vehicle is blacklisted."); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You cannot spawn vehicles in DM zone!"); return; } if (!Enum.IsDefined(typeof(VehicleModel), Alt.Hash(vehicleName))) { - player.SendChatMessage("{FF0000} Invalid vehicle model!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "Invalid vehicle model!"); + return; + } + + if (!VehicleController.CheckVehicle(vehicleName) && !player.IsAdmin) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Vehicle is not available!"); + if (VehicleController.IsWhitelist) player.SendChatMessage("Available vehicles: " + string.Join(", ", VehicleController.List)); return; } - + if (player.InteriorLocation != 0) { - player.SendChatMessage("{FF0000} You can't spawn vehicles in interiors!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You can't spawn vehicles in interiors!"); return; } if (Alt.GetAllVehicles().Any(veh => veh.Position.Distance(player.Position) < 3)) { - player.SendChatMessage("{FF0000} You are too close to a vehicle!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You are too close to a vehicle!"); return; } if (player.LastVehicleSpawn.AddSeconds(10) > DateTime.Now) { - player.SendChatMessage("{FF0000} You have to wait 10s before spawning a new vehicle!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You have to wait 10s before spawning a new vehicle!"); return; } @@ -52,19 +67,19 @@ public void SpawnVeh(IAltPlayer player, string vehicleName) var target = player.Vehicles.OrderBy(veh => veh.SpawnTime).First(); player.Vehicles.Remove(target); target.Destroy(); - player.SendChatMessage("{FF0000} You can't have more than 3 vehicles. We removed your oldest one!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You can't have more than 3 vehicles. We removed your oldest one!"); } if (player.IsInVehicle) { - player.SendChatMessage("{FF0000} You are already in a vehicle we replaced it for you!"); + player.SendChatMessage(ChatConstants.ErrorPrefix + "You are already in a vehicle we replaced it for you!"); player.Vehicle.Destroy(); return; } - lock (StatsHandler.StatsData) + lock (StatsController.StatsData) { - StatsHandler.StatsData.VehiclesSpawned++; + StatsController.StatsData.VehiclesSpawned++; } var spawnedVeh = (AltVehicle) Alt.CreateVehicle(Alt.Hash(vehicleName), @@ -75,25 +90,6 @@ public void SpawnVeh(IAltPlayer player, string vehicleName) spawnedVeh.Owner = player; } - // [Command("spectate")] - // public void Spectate(IAltPlayer player) - // { - // // Disable - // if (player.GhostMode) - // { - // player.SendChatMessage("{00FF00} Spectator Mode disabled! You're no longer invincible."); - // player.Emit("ghost_mode", false); - // player.GhostMode = false; - // player.DeleteStreamSyncedMetaData("spectator"); - // return; - // } - // // Enable - // player.GhostMode = true; - // player.Emit("ghost_mode", true); - // player.SendChatMessage("{00FF00} Spectator Mode enabled! You're now invincible."); - // player.SetStreamSyncedMetaData("spectator", true); - // } - [Command("weapons")] public void GetWeapons(IAltPlayer player) { @@ -105,34 +101,35 @@ public void GetWeapons(IAltPlayer player) } } - [Command("model")] - public void ChangeModel(IAltPlayer player) - { - if (player.Model == Alt.Hash("mp_m_freemode_01")) - { - player.Model = Alt.Hash("mp_f_freemode_01"); - } - else - { - player.Model = Alt.Hash("mp_m_freemode_01"); - } - - player.RefreshFace(); - - player.RefreshClothes(); - player.SendChatMessage( - $"{{00FF00}}Your model changed"); - } + // TODO fix in core + // [Command("model")] + // public async Task ChangeModel(IAltPlayer player) + // { + // if (player.Model == Alt.Hash("mp_m_freemode_01")) + // { + // player.Model = Alt.Hash("mp_f_freemode_01"); + // } + // else + // { + // player.Model = Alt.Hash("mp_m_freemode_01"); + // } + // player.Spawn(player.Position); + // + // // AppearanceController.RefreshFace(player); + // // await AppearanceController.RefreshClothes(player); + // + // player.SendChatMessage(ChatConstants.SuccessPrefix + $"Your model was changed"); + // } [Command("outfit")] - public void Outfit(IAltPlayer player, string outfitUniqueName = "") + public async Task Outfit(IAltPlayer player, string outfitUniqueName = "") { if (string.IsNullOrEmpty(outfitUniqueName)) { - player.RefreshClothes(); + await AppearanceController.RefreshClothes(player); return; } - player.EquipOutfit(Alt.Hash(outfitUniqueName)); + AppearanceController.EquipOutfit(player, Alt.Hash(outfitUniqueName)); player.SendChatMessage( $"{{00FF00}}Your outfit updated"); } @@ -143,7 +140,7 @@ public void Teleport(IAltPlayer player, int id = 0) if (id > Misc.SpawnPositions.Length || id <= 0) { player.SendChatMessage( - $"{{FF0000}}Invalid Spawnpoint! (Minimum 1, Maximum: {Misc.SpawnPositions.Length})"); + ChatConstants.ErrorPrefix + $"Invalid Spawnpoint! (Minimum 1, Maximum: {Misc.SpawnPositions.Length})"); return; } @@ -151,63 +148,6 @@ public void Teleport(IAltPlayer player, int id = 0) player.Position = spawnpoint + new Position(_random.Next(0, 10), _random.Next(0, 10), 0); } - [Command("ban")] - public void Ban(IAltPlayer player, int id) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (player.Id == id) - { - player.SendChatMessage("{FF0000} You can't ban yourself!"); - return; - } - - var target = (IAltPlayer)Alt.GetAllPlayers().FirstOrDefault(p => p.Id == id); - if (target == null) - { - player.SendChatMessage($"{{FF0000}}Player with id {id} not found!"); - return; - } - - target.Kick("You've been banned from this server!"); - Misc.BannedPlayers.Add(target.CloudID); - string json = JsonSerializer.Serialize(Misc.BannedPlayers); - File.WriteAllText(@"BannedPlayers.json", json); - - player.SendChatMessage($"{{00FF00}}Player with id {id} banned!"); - } - - [Command("unban")] - public void Unban(IAltPlayer player, string rsid) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var target = Misc.BannedPlayers.FirstOrDefault(id => id == rsid); - if (target == null) - { - player.SendChatMessage($"{{FF0000}}Player with rsid {rsid} not found!"); - return; - } - - if (Misc.BannedPlayers.All(id => id != rsid)) - { - player.SendChatMessage($"{{FF0000}}Player with hwid {rsid} not banned!"); - return; - } - - // remove banned player from list - Misc.BannedPlayers.Remove(rsid); - player.SendChatMessage($"{{00FF00}}Player with hwid {rsid} unbanned!"); - } - [Command("addcomponent")] public void WeaponComponent(IAltPlayer player, string name) { @@ -255,191 +195,14 @@ public void Dm(IAltPlayer player) } } - [Command("togglechat")] - public void ToggleChat(IAltPlayer player, bool state) - { - // check if player is operator - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - player.SendChatMessage("{00FF00} Chat is now " + (state ? "enabled" : "disabled") + "!"); - Misc.ChatState = state; - foreach (var p in Alt.GetAllPlayers()) - { - // check if player is operator - if (player.IsAdmin) continue; - p.Emit("set_chat_state", state); - } - } - - [Command("dimension")] - public void Dimension(IAltPlayer player, int dimension = 0) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - player.Dimension = dimension; - } - [Command("clearvehicles")] public void ClearVehicles(IAltPlayer player) { - // get all vehicles owned by player foreach (var veh in player.Vehicles) { veh.Destroy(); } - } - - [Command("tpallhere")] - public void TpAllhere(IAltPlayer player) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - foreach (var p in Alt.GetAllPlayers()) - { - if (p is not { } target) continue; - target.Position = player.Position; - target.SendChatMessage("{00FF00} You were teleported to " + player.Name + "!"); - } - } - - [Command("tphere")] - public void TpHere(IAltPlayer player, int target) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var targetPlayer = Alt.GetAllPlayers().FirstOrDefault(p => p.Id == target); - if (targetPlayer == null) - { - player.SendChatMessage("{FF0000} Player not found!"); - return; - } - - targetPlayer.Position = player.Position; - targetPlayer.SendChatMessage("{00FF00} You were teleported to " + player.Name + "!"); - } - - [Command("tpto")] - public void TpTo(IAltPlayer player, int target) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var targetPlayer = Alt.GetAllPlayers().FirstOrDefault(p => p.Id == target); - if (targetPlayer == null) - { - player.SendChatMessage("{FF0000} Player not found!"); - return; - } - - player.Position = targetPlayer.Position; - player.SendChatMessage("{00FF00} You were teleported to " + targetPlayer.Name + "!"); - } - - [Command("clearallvehicles")] - public void ClearAllVehicles(IAltPlayer player, int distance = 0) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (distance == 0) - { - foreach (var veh in Alt.GetAllVehicles()) - { - veh.Destroy(); - } - - return; - } - - var distSqr = distance * distance; - foreach (var veh in Alt.GetAllVehicles()) - { - // compare squared distance between player and vehicle - if (Vector3.DistanceSquared(veh.Position, player.Position) <= distSqr) veh.Destroy(); - } - } - - [Command("settime")] - public void SetTime(IAltPlayer player, int hour) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (hour > 23 || hour < 0) - { - player.SendChatMessage("{FF0000} Invalid hour!"); - return; - } - - foreach (var p in Alt.GetAllPlayers()) - { - p.SetDateTime(0, 0, 0, hour, 0, 0); - } - } - - [Command("setweather")] - public void SetWeather(IAltPlayer player, uint weather) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (weather > 14) - { - player.SendChatMessage("{FF0000} Invalid weather!"); - return; - } - - foreach (var p in Alt.GetAllPlayers()) - { - p.SetWeather(weather); - } - - Misc.Weather = weather; - } - - [Command("noclip")] - public void NoClip(IAltPlayer player) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - player.NoClip = !player.NoClip; - player.Streamed = !player.NoClip; - player.Visible = !player.NoClip; - player.SendChatMessage($"{{00FF00}}NoClip is now {(player.NoClip ? "enabled" : "disabled")}!"); - - player.Emit("noclip", player.NoClip); + player.SendChatMessage(ChatConstants.SuccessPrefix + "You removed all your vehicles!"); } [Command("revive")] @@ -448,168 +211,15 @@ public void Respawn(IAltPlayer player) if (Misc.AdminOverridedSpawnPos is not null) player.Spawn((Position) Misc.AdminOverridedSpawnPos); else player.Spawn(player.Position); player.ClearBloodDamage(); + player.Health = 200; } - - [Command("announce")] - public void Announce(IAltPlayer player, string header, int time, params string[] body) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var message = string.Join(" ", body); - Alt.EmitAllClients("announce", header, message, time); - } - - [Command("tpcoords")] - public void TpCoords(IAltPlayer player, int x, int y, int z) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - player.Position = new Vector3(x, y, z); - player.SendChatMessage($"{{00FF00}} You were teleported to {x}, {y}, {z}!"); - } - - [Command("kick")] - public void Kick(IAltPlayer player, int id) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (player.Id == id) - { - player.SendChatMessage("{FF0000} You can't kick yourself!"); - return; - } - - var target = Alt.GetAllPlayers().FirstOrDefault(p => p.Id == id); - if (target == null) - { - player.SendChatMessage($"{{FF0000}}Player with id {id} not found!"); - return; - } - - target.Kick("You've been kicked from this server!"); - - player.SendChatMessage($"{{00FF00}}Player with id {id} kicked!"); - } - - [Command("godmode")] - public void Godmode(IAltPlayer player, int id) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var target = Alt.GetAllPlayers().FirstOrDefault(p => p.Id == id); - if (target == null) - { - player.SendChatMessage($"{{FF0000}}Player with id {id} not found!"); - return; - } - - target.Invincible = !target.Invincible; - target.SendChatMessage( - $"{(target.Invincible ? "{00FF00}" : "{FF0000}")}Godmode {(target.Invincible ? "on" : "off")}!"); - - if (player.Id != target.Id) - player.SendChatMessage($"{{00FF00}}Godmode {(target.Invincible ? "on" : "off")}!"); - } - - [Command("overridespawnpos")] - public void OverrideSpawnPos(IAltPlayer player, bool mode) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (mode) - { - var pos = player.Position; - Misc.AdminOverridedSpawnPos = pos; - - player.SendChatMessage( - $"{{00FF00}} You're overrided spawn position for all player on {pos.X}, {pos.Y}, {pos.Z}!"); - } - else - { - Misc.AdminOverridedSpawnPos = null; - player.SendChatMessage($"{{00FF00}} You're no longer overrided spawn position!"); - } - } - + [Command("getpos")] public void GetPosition(IAltPlayer player) { var pos = player.Position; - player.SendChatMessage($"{{00FF00}} Your position is {pos.X}, {pos.Y}, {pos.Z}!"); + player.SendChatMessage(ChatConstants.SuccessPrefix + $"Your position is {pos.X}, {pos.Y}, {pos.Z}!"); player.Emit("get_pos"); } - - [Command("godmodeall")] - public void GodmodeAllPlayers(IAltPlayer player, bool mode) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - var targets = Alt.GetAllPlayers().ToList(); - - foreach (var target in targets) - { - target.Invincible = mode; - target.SendChatMessage($"{{00FF00}}Godmode for all players is {(mode ? "activated" : "deactivated")}!"); - } - } - - [Command("esp")] - public void Esp(IAltPlayer player, bool mode) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - player.Emit("esp", mode); - } - - [Command("globalvoice")] - public void GlobalVoice(IAltPlayer player) - { - if (!player.IsAdmin) - { - player.SendChatMessage("{FF0000} No permission!"); - return; - } - - if (Voice.IsGlobalVoiceEnabled(player)) - { - Voice.EnableGlobalVoice(player); - player.SendChatMessage("{00FF00} Global voice enabled!"); - return; - } - else - { - Voice.DisableGlobalVoice(player); - player.SendChatMessage("{00FFFF} Global voice disabled!"); - return; - } - } } } \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Constants/ChatConstants.cs b/freeroam-extended/server/freeroam-extended/Constants/ChatConstants.cs new file mode 100644 index 0000000..9d3542f --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Constants/ChatConstants.cs @@ -0,0 +1,10 @@ +namespace Freeroam_Extended +{ + public static class ChatConstants + { + public static string ErrorPrefix = "{e86f66}"; + public static string SuccessPrefix = "{52c765}"; + public static string AdminPrefix = "{e39959}"; + public static string NoPermissions = ErrorPrefix + "No permissions!"; + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Constants/VehicleConstants.cs b/freeroam-extended/server/freeroam-extended/Constants/VehicleConstants.cs new file mode 100644 index 0000000..2cb86ad --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Constants/VehicleConstants.cs @@ -0,0 +1,144 @@ + +namespace Freeroam_Extended +{ + public static class VehicleConstants + { + public static List DefaultWhitelistModels = new(); + public static List DefaultBlacklistModels = new() + { + "impaler2", + "dinghy", + "nokota", + "tula", + "swift2", + "technical2", + "akula", + "seasparrow2", + "issi6", + "caracara", + "kosatka", + "technical3", + "paragon2", + "toreador", + "deluxo", + "thruster", + "trailerlarge", + "issi5", + "scarab2", + "valkyrie2", + "comet4", + "molotok", + "ardent", + "seasparrow3", + "imperator2", + "pounder2", + "strikeforce", + "monster3", + "slamvan6", + "dune3", + "cerberus3", + "firetruk", + "mule4", + "frogger2", + "brutus3", + "menacer", + "oppressor2", + "insurgent2", + "brutus", + "avenger", + "speedo4", + "technical", + "slamvan4", + "bruiser3", + "terbyte", + "havok", + "impaler3", + "insurgent3", + "brutus2", + "trailersmall2", + "insurgent", + "volatus", + "deathbike2", + "microlight", + "impaler4", + "starling", + "bruiser2", + "riot2", + "supervolito2", + "maverick", + "valkyrie", + "blazer5", + "dinghy2", + "zr3803", + "khanjali", + "pyro", + "dominator5", + "deathbike3", + "annihilator2", + "dominator6", + "lazer", + "minitank", + "vigilante", + "tampa3", + "scarab", + "zr3802", + "dinghy5", + "rogue", + "cerberus", + "polmav", + "imperator3", + "mogul", + "seasparrow", + "monster5", + "chernobog", + "dominator4", + "scramjet", + "scarab3", + "slamvan5", + "predator", + "revolter", + "seabreeze", + "viseris", + "jb7002", + "swift", + "patrolboat", + "barrage", + "avenger2", + "limo2", + "savage", + "hunter", + "bombushka", + "halftrack", + "deathbike", + "nightshark", + "imperator", + "volatol", + "dinghy3", + "zr380", + "apc", + "issi4", + "bruiser", + "cerberus2", + "boxville5", + "supervolito", + "frogger", + "buzzard2", + "rhino", + "buzzard", + "annihilator", + "monster4", + "dinghy4", + "oppressor", + "stromberg", + "savestra", + "ruiner2", + "hydra", + "jet", + "titan", + "blimp", + "cargoplane", + "blimp2", + "blimp3" + }; + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/AppearanceController.cs b/freeroam-extended/server/freeroam-extended/Controllers/AppearanceController.cs new file mode 100644 index 0000000..c3f8cf4 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/AppearanceController.cs @@ -0,0 +1,120 @@ +using Freeroam_Extended.Clothes; +using Freeroam_Extended.Factories; + +namespace Freeroam_Extended; + +public class AppearanceController +{ + + public static void RefreshFace(IAltPlayer player) + { + if (player.Sex == 1) + { + player.SetHeadBlendData(6, 21, 0, 6, 21, 0, 0.41f, 0.18f, 0.0f); + player.SetHeadOverlay(0, 255, 1.0f); + player.SetHeadOverlay(1, 255, 1.0f); + player.SetHeadOverlay(2, 30, 1.0f); + player.SetHeadOverlay(3, 255, 1.0f); + player.SetHeadOverlay(4, 14, 1.0f); + player.SetHeadOverlay(5, 1, 1.0f); + player.SetHeadOverlay(6, 10, 0.85f); + player.SetHeadOverlay(7, 255, 1.0f); + player.SetHeadOverlay(8, 2, 1.0f); + player.SetHeadOverlay(9, 0, 0.0f); + player.SetHeadOverlay(10, 255, 1.0f); + player.SetHeadOverlay(11, 255, 1.0f); + player.SetHeadOverlay(12, 255, 1.0f); + + player.SetHeadOverlayColor(5, 2, 11, 0); + player.SetHeadOverlayColor(8, 2, 6, 0); + + int hairs = Misc.RandomInt(1, 23); + int hairsColor = Misc.RandomInt(1, 63); + int hairsColor2 = Misc.RandomInt(1, 63); + + player.SetClothes(2, (ushort)hairs, 0, 0); + player.HairColor = (byte)hairsColor; + player.HairHighlightColor = (byte)hairsColor2; + player.SetEyeColor(2); + + float[] featureParams = { -0.78f, 0, 0, -0.07f, 0.03f, 0, 0.07f, -0.44f, 0.07f, 0.02f, -0.95f, -0.74f, -1, -0.09f, -0.57f, 0.02f, -0.1f, -0.19f, -1, -1 }; + for (int i = 0; i < featureParams.Length; i++) + { + player.SetFaceFeature((byte)i, featureParams[i]); + } + } + else if (player.Sex == 0) + { + player.SetHeadBlendData(2, 21, 0, 2, 21, 0, 0.5f, 0.72f, 0.0f); + player.SetHeadOverlay(0, 255, 1.0f); + player.SetHeadOverlay(1, 255, 1.0f); + player.SetHeadOverlay(2, 30, 1.0f); + player.SetHeadOverlay(3, 255, 1.0f); + player.SetHeadOverlay(4, 255, 1.0f); + player.SetHeadOverlay(5, 255, 1.0f); + player.SetHeadOverlay(6, 255, 1.0f); + player.SetHeadOverlay(7, 255, 1.0f); + player.SetHeadOverlay(8, 0, 0.15f); + player.SetHeadOverlay(9, 255, 1.0f); + player.SetHeadOverlay(10, 255, 1.0f); + player.SetHeadOverlay(11, 255, 1.0f); + player.SetHeadOverlay(12, 255, 1.0f); + + player.SetHeadOverlayColor(5, 2, 32, 0); + player.SetHeadOverlayColor(8, 2, 11, 0); + + int hairs = Misc.RandomInt(1, 22); + int hairsColor = Misc.RandomInt(1, 63); + int hairsColor2 = Misc.RandomInt(1, 63); + + player.SetClothes(2, (ushort)hairs, 0, 0); + player.HairColor = (byte)hairsColor; + player.HairHighlightColor = (byte)hairsColor2; + player.SetEyeColor(3); + + float[] featureParams = { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }; + for (int i = 0; i < featureParams.Length; i++) + { + player.SetFaceFeature((byte)i, featureParams[i]); + } + } + } + + public static async Task RefreshClothes(IAltPlayer player) + { + if (!Misc.IsResourceLoaded("c_clothesfit")) + return; + + if (player.Sex == 2) + return; + + await ClothesFitService.DestroyPlayer(player); + await ClothesFitService.InitPlayer(player); + + ulong[] outfits = await ClothesFitService.GetOutfitsBySex(player.Sex); + + int index = Misc.RandomInt(0, outfits.Length - 1); + ulong randomElement = outfits[index]; + + await ClothesFitService.Equip(player, (uint)randomElement); + } + + public static async Task EquipOutfit(IAltPlayer player, uint outfitHash) + { + if (!Misc.IsResourceLoaded("c_clothesfit")) + return; + + if (player.Sex == 2) + return; + + await ClothesFitService.DestroyPlayer(player); + await ClothesFitService.InitPlayer(player); + + ulong[] outfits = await ClothesFitService.GetOutfitsBySex(player.Sex); + + if (outfits.Contains(outfitHash)) + { + await ClothesFitService.Equip(player, outfitHash); + } + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/ChatController.cs b/freeroam-extended/server/freeroam-extended/Controllers/ChatController.cs new file mode 100644 index 0000000..14e3915 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/ChatController.cs @@ -0,0 +1,62 @@ +using System.Text.Json; +using AltV.Net; +using AltV.Net.Elements.Entities; +using AltV.Net.Resources.Chat.Api; +using Freeroam_Extended.Factories; + +namespace Freeroam_Extended; + +public static class ChatController +{ + public static void Init() + { + Alt.OnClient("chat:message", OnChatMessage); + } + + public static bool ChatState = false; + + public static void Broadcast(string message) + { + Alt.EmitAllClients("chat:message", null, (object) message); + } + + public static void BroadcastAdmins(string message) + { + message = ChatConstants.AdminPrefix + message; + + foreach (var p in Alt.GetAllPlayers().Where(e => ((IAltPlayer) e).IsAdmin)) + { + p.SendChatMessage(message); + } + } + + private static void OnChatMessage(IAltPlayer player, params string[] args) + { + var message = string.Join("", args); + if (args.Length == 0 || message.Length == 0) return; + if (args[0].StartsWith("/")) return; + + if (player.Data.Muted) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "You are muted!"); + return; + } + + if (!ChatState && !player.IsAdmin) + { + player.SendChatMessage(ChatConstants.ErrorPrefix + "Chat is disabled!"); + return; + } + + foreach (var p in Alt.GetAllPlayers()) + { + p.Emit("chat:message", (player.IsAdmin ? "{008736}" : "{FFFFFF}") + player.Serialize(), "{FFFFFF}" + message); + } + } + + public static void Mute(IAltPlayer player) + { + + } + +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/PlayerController.cs b/freeroam-extended/server/freeroam-extended/Controllers/PlayerController.cs new file mode 100644 index 0000000..24a1588 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/PlayerController.cs @@ -0,0 +1,105 @@ +using System.Text.Json; +using AltV.Net; +using AltV.Net.Elements.Entities; +using Freeroam_Extended.Factories; + +namespace Freeroam_Extended; + +public static class PlayerController +{ + private static readonly string BannedPlayersFile = "BannedPlayers.json"; + private static readonly string PlayerDataFile = "PlayersData.json"; + + public static HashSet Banned = new(); + public static Dictionary PlayerData = new(); + + public static void Init() + { + if (File.Exists(PlayerDataFile)) + { + var json = File.ReadAllText(PlayerDataFile); + try + { + PlayerData = JsonSerializer.Deserialize>(json) ?? new(); + } + catch (Exception e) + { + Alt.LogError("Failed to parse operators file!"); + Alt.LogError(e.ToString()); + } + } + + if (File.Exists(BannedPlayersFile)) + { + var json = File.ReadAllText(BannedPlayersFile); + try + { + Banned = JsonSerializer.Deserialize>(json) ?? new HashSet(); + } + catch (Exception e) + { + Alt.LogError("Failed to parse banned players file!"); + Alt.LogError(e.ToString()); + } + } + } + + private static void SaveBanned() + { + File.WriteAllText(BannedPlayersFile, JsonSerializer.Serialize(Banned)); + } + + public static void Ban(IAltPlayer player) + { + player.Kick("You are banned!"); + Banned.Add(player.CloudID); + SaveBanned(); + } + + public static bool IsBanned(string cloudId) + { + return Banned.Contains(cloudId); + } + + private static void SavePlayerData() + { + File.WriteAllText(PlayerDataFile, JsonSerializer.Serialize(PlayerData)); + } + + private static void ApplyPlayerData(IAltPlayer player) + { + PlayerData[player.CloudID] = player.Data; + player.SetLocalMetaData("operator", player.Data.Operator); + if (player.Data.Muted) VoiceController.MutePlayer(player); + else VoiceController.UnmutePlayer(player); + SavePlayerData(); + } + + public static void Op(IAltPlayer target, IAltPlayer? executor) + { + target.Data.Operator = true; + ApplyPlayerData(target); + ChatController.BroadcastAdmins((executor?.Serialize() ?? "SERVER") + " gave " + target.Serialize() + " operator permissions"); + } + + public static void Deop(IAltPlayer target, IAltPlayer? executor) + { + target.Data.Operator = false; + ApplyPlayerData(target); + ChatController.BroadcastAdmins((executor?.Serialize() ?? "SERVER") + " removed " + target.Serialize() + " operator permissions"); + } + + public static void Mute(IAltPlayer target, IAltPlayer? executor) + { + target.Data.Muted = true; + ApplyPlayerData(target); + ChatController.BroadcastAdmins((executor?.Serialize() ?? "SERVER") + " muted " + target.Serialize()); + } + + public static void Unmute(IAltPlayer target, IAltPlayer? executor) + { + target.Data.Muted = false; + ApplyPlayerData(target); + ChatController.BroadcastAdmins((executor?.Serialize() ?? "SERVER") + " unmuted " + target.Serialize()); + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/StatsController.cs b/freeroam-extended/server/freeroam-extended/Controllers/StatsController.cs new file mode 100644 index 0000000..b914139 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/StatsController.cs @@ -0,0 +1,79 @@ +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using AltV.Net; + +namespace Freeroam_Extended +{ + public static class StatsController + { + private static readonly string UniquePlayersFile = "UniquePlayers.json"; + private static readonly string StatsFile = "Stats.json"; + + public static HashSet UniquePlayers = new(); + public static Stats StatsData = new (); + + public static void Init() + { + if (File.Exists(UniquePlayersFile)) + { + var json = File.ReadAllText(UniquePlayersFile); + try + { + UniquePlayers = JsonSerializer.Deserialize>(json) ?? new(); + } + catch (Exception e) + { + Alt.LogError("Failed to parse unique players file!"); + Alt.LogError(e.ToString()); + } + } + + if (File.Exists(StatsFile)) + { + var json = File.ReadAllText(StatsFile); + try + { + StatsData = JsonSerializer.Deserialize(json) ?? new(); + } + catch (Exception e) + { + Alt.LogError("Failed to parse stats file!"); + Alt.LogError(e.ToString()); + } + } + } + + public static void UpdateStats() + { + File.WriteAllText(StatsFile, JsonSerializer.Serialize(StatsData)); + } + + public static void UpdateUniquePlayers() + { + File.WriteAllText(UniquePlayersFile, JsonSerializer.Serialize(UniquePlayers)); + } + + public static void AddUniquePlayer(string cloudId) + { + if (!UniquePlayers.Contains(cloudId)) + { + UniquePlayers.Add(cloudId); + lock (StatsData) + { + StatsData.UniquePlayers++; + } + UpdateUniquePlayers(); + } + } + } + + public class Stats + { + public int VehiclesSpawned { get; set; } + public int VehiclesDestroyed { get; set; } + public int PlayerDeaths { get; set; } + public int PlayerConnections { get; set; } + public int UniquePlayers { get; set; } + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/VehicleController.cs b/freeroam-extended/server/freeroam-extended/Controllers/VehicleController.cs new file mode 100644 index 0000000..f9e96c2 --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/VehicleController.cs @@ -0,0 +1,148 @@ +using System.Text.Json; +using AltV.Net; +using AltV.Net.Resources.Chat.Api; +using Freeroam_Extended.Factories; + +namespace Freeroam_Extended; + +class VehicleListFile +{ + public bool IsWhitelist { get; set; } + public List List { get; set; } +} + +public static class VehicleController +{ + private static readonly string VehicleListFile = "VehicleList.json"; + + public static bool IsWhitelist { get; set; } + public static string State => IsWhitelist ? "whitelist" : "blacklist"; + + public static List List { get; set; } = new(); + public static HashSet ListHashes { get; set; } = new(); + + public static void Init() + { + IsWhitelist = false; + List = VehicleConstants.DefaultBlacklistModels; + + if (File.Exists(VehicleListFile)) + { + var json = File.ReadAllText(VehicleListFile); + try + { + var data = JsonSerializer.Deserialize(json) ?? new(); + IsWhitelist = data.IsWhitelist; + List = data.List; + } + catch (Exception e) + { + Alt.LogError("Failed to parse vehicle list file!"); + Alt.LogError(e.ToString()); + } + } + + UpdateHashes(); + } + + public static void Save() + { + var data = new VehicleListFile + { + IsWhitelist = IsWhitelist, + List = List + }; + File.WriteAllText(VehicleListFile, JsonSerializer.Serialize(data)); + } + + public static bool CheckVehicle(string model) + { + if (IsWhitelist) + { + return ListHashes.Contains(Alt.Hash(model)); + } + else + { + return !ListHashes.Contains(Alt.Hash(model)); + } + } + + public static bool CheckVehicle(uint model) + { + if (IsWhitelist) + { + return ListHashes.Contains(model); + } + else + { + return !ListHashes.Contains(model); + } + } + + private static void UpdateHashes() + { + ListHashes = List.Select(Alt.Hash).ToHashSet(); + } + + public static void UpdateVehicles() + { + foreach (var altVehicle in Alt.GetAllVehicles()) + { + var vehicle = (IAltVehicle)altVehicle; + if (vehicle.Owner is { IsAdmin: true }) continue; + if (CheckVehicle(vehicle.Model)) continue; + + vehicle.Owner.SendChatMessage(ChatConstants.ErrorPrefix + "Your vehicle was removed!"); + vehicle.Destroy(); + } + } + + public static void Allow(string model) + { + if (IsWhitelist) + { + List.Add(model); + } + else + { + List.Remove(model); + } + + UpdateHashes(); + Save(); + UpdateVehicles(); + } + + public static void Block(string model) + { + if (IsWhitelist) + { + List.Remove(model); + } + else + { + List.Add(model); + } + + UpdateHashes(); + Save(); + UpdateVehicles(); + } + + public static void UpdateState(bool whitelist) + { + IsWhitelist = whitelist; + List = whitelist ? VehicleConstants.DefaultWhitelistModels : VehicleConstants.DefaultBlacklistModels; + UpdateHashes(); + Save(); + UpdateVehicles(); + } + + public static void Clear() + { + List = new(); + UpdateHashes(); + Save(); + UpdateVehicles(); + } +} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Controllers/VoiceController.cs b/freeroam-extended/server/freeroam-extended/Controllers/VoiceController.cs new file mode 100644 index 0000000..6d1217c --- /dev/null +++ b/freeroam-extended/server/freeroam-extended/Controllers/VoiceController.cs @@ -0,0 +1,64 @@ +using AltV.Net.Async; +using AltV.Net; +using AltV.Net.Elements.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Freeroam_Extended +{ + static internal class VoiceController + { + public static IVoiceChannel LocalChannel = null!; + public static IVoiceChannel GlobalChannel = null!; + + public static void Init() + { + LocalChannel = Alt.CreateVoiceChannel(true, 100); + GlobalChannel = Alt.CreateVoiceChannel(false, 0); + } + + public static void AddPlayer(IPlayer player) + { + LocalChannel.AddPlayer(player); + GlobalChannel.AddPlayer(player); + + GlobalChannel.MutePlayer(player); + } + + public static void RemovePlayer(IPlayer player) + { + LocalChannel.RemovePlayer(player); + GlobalChannel.RemovePlayer(player); + + GlobalChannel.MutePlayer(player); + } + + public static void MutePlayer(IPlayer player) + { + LocalChannel.MutePlayer(player); + } + + public static void UnmutePlayer(IPlayer player) + { + LocalChannel.UnmutePlayer(player); + } + + public static void EnableGlobalVoice(IPlayer player) + { + GlobalChannel.UnmutePlayer(player); + } + + public static void DisableGlobalVoice(IPlayer player) + { + GlobalChannel.MutePlayer(player); + } + + public static bool IsGlobalVoiceEnabled(IPlayer player) + { + return GlobalChannel.IsPlayerMuted(player); + } + } +} diff --git a/freeroam-extended/server/freeroam-extended/EventHandler.cs b/freeroam-extended/server/freeroam-extended/EventHandler.cs index 2fe415e..710d8d9 100644 --- a/freeroam-extended/server/freeroam-extended/EventHandler.cs +++ b/freeroam-extended/server/freeroam-extended/EventHandler.cs @@ -28,8 +28,13 @@ public EventHandler() #endif } - altPlayer.EventCount++; - if (altPlayer.EventCount > 100) altPlayer.Kick("Event count exceeded"); + if (altPlayer.EventCount > 100) + { + altPlayer.Kick("Event count exceeded"); + return; + } + + altPlayer.IncrementEventCount(); }; } @@ -38,18 +43,21 @@ public EventHandler() [AsyncScriptEvent(ScriptEventType.PlayerConnect)] public async Task OnPlayerConnect(IAltPlayer player, string reason) { - string cloudId = await player.RequestCloudId(); - if (cloudId == "invalid") + string cloudId = ""; + + try + { + cloudId = await player.RequestCloudId(); + } + catch (Exception e) { player.Kick("Authorization error"); AltAsync.Log( - $"HWID: {player.HardwareIdHash}, RS ID: {cloudId}. Tried to join the server with invalid RS ID."); - return; + $"HWID: {player.HardwareIdHash}. Tried to join the server with invalid RS ID: {e}"); } - player.CloudID = cloudId; - if (Misc.BannedPlayers.Contains(player.CloudID)) + if (PlayerController.IsBanned(player.CloudID)) { player.Kick("You're banned from this server!"); AltAsync.Log( @@ -57,57 +65,48 @@ public async Task OnPlayerConnect(IAltPlayer player, string reason) return; } - if (Misc.Operators.Contains(cloudId)) - player.IsAdmin = true; + if (PlayerController.PlayerData.TryGetValue(player.CloudID, out var data)) + { + player.Data = data; + } // select random entry from SpawnPoints var randomSpawnPoint = Misc.AdminOverridedSpawnPos is not null ? Misc.AdminOverridedSpawnPos : Misc.SpawnPositions.ElementAt(_random.Next(0, Misc.SpawnPositions.Length)); + player.Spawn((Position)randomSpawnPoint + new Position(_random.Next(0, 10), _random.Next(0, 10), 0)); player.Model = (uint)PedModel.FreemodeMale01; player.SetDateTime(DateTime.UtcNow); player.SetWeather(Misc.Weather); - player.Emit("draw_dmzone", Misc.DMPos.X, Misc.DMPos.Y, Misc.DMRadius, 150); - - if (player.IsAdmin) - { - player.Emit("set_chat_state", true); - } - else - { - player.Emit("set_chat_state", Misc.ChatState); - } + player.Emit("draw_dmzone", Misc.DMPos.X, Misc.DMPos.Y, Misc.DMRadius); - lock (StatsHandler.StatsData) + lock (StatsController.StatsData) { - StatsHandler.StatsData.PlayerConnections++; - if (!Misc.UniquePlayers.Contains(player.CloudID)) - { - StatsHandler.StatsData.UniquePlayers++; - Misc.UniquePlayers.Add(player.CloudID); - File.WriteAllText(@"UniquePlayers.json", JsonSerializer.Serialize(Misc.UniquePlayers)); - } + StatsController.StatsData.PlayerConnections++; } - Voice.AddPlayer(player); + StatsController.AddUniquePlayer(player.CloudID); + + VoiceController.AddPlayer(player); + if (player.Data.Muted) VoiceController.MutePlayer(player); if (Misc.IsResourceLoaded("c_clothesfit")) { await ClothesFitService.InitPlayer(player); } - player.RefreshFace(); - await player.RefreshClothes(); + AppearanceController.RefreshFace(player); + await AppearanceController.RefreshClothes(player); } [ScriptEvent(ScriptEventType.VehicleDestroy)] public void OnVehicleDestroy(IAltVehicle target) { - lock (StatsHandler.StatsData) + lock (StatsController.StatsData) { - StatsHandler.StatsData.VehiclesDestroyed++; + StatsController.StatsData.VehiclesDestroyed++; } target.Owner.SendChatMessage("Your Vehicle got destroyed. We removed it for you!"); @@ -117,7 +116,7 @@ public void OnVehicleDestroy(IAltVehicle target) [ScriptEvent(ScriptEventType.PlayerDisconnect)] public void OnPlayerDisconnect(IAltPlayer player, string reason) { - Voice.RemovePlayer(player); + VoiceController.RemovePlayer(player); var vehicles = player.Vehicles; @@ -137,77 +136,55 @@ public async Task OnPlayerDead(IAltPlayer player, IEntity killer, uint weapon) { var spawnPointPool = player.DmMode ? Misc.AirportSpawnPositions : Misc.SpawnPositions; - var randomSpawnPoint = spawnPointPool.ElementAt(_random.Next(0, spawnPointPool.Length)); + var randomSpawnPoint = Misc.AdminOverridedSpawnPos ?? spawnPointPool.ElementAt(_random.Next(0, spawnPointPool.Length)); player.Spawn(randomSpawnPoint + new Position(_random.Next(0, 10), _random.Next(0, 10), 0)); - lock (StatsHandler.StatsData) + lock (StatsController.StatsData) { - StatsHandler.StatsData.PlayerDeaths++; + StatsController.StatsData.PlayerDeaths++; } if (killer is not IAltPlayer killerPlayer) return; if (!Misc.BlacklistedWeapons.Contains(weapon)) return; - Alt.Core.LogColored( - $"~r~ Banned Player: {killerPlayer.Name} ({killerPlayer.Id}) for using illegal weapon!"); - Misc.BannedPlayers.Add(killerPlayer.CloudID); - string json = JsonSerializer.Serialize(Misc.BannedPlayers); - await File.WriteAllTextAsync(@"BannedPlayers.json", json); - killerPlayer.Kick("You're banned from this server!"); + + var name = killerPlayer.Serialize(); + PlayerController.Ban(killerPlayer); + ChatController.BroadcastAdmins($"Banned player {name} for using illegal weapon!"); } - [AsyncScriptEvent(ScriptEventType.ConsoleCommand)] - public async Task OnConsoleCommand(string name, string[] args) + [ScriptEvent(ScriptEventType.ConsoleCommand)] + public void OnConsoleCommand(string name, string[] args) { - var playerPool = Alt.GetAllPlayers(); switch (name) { case "op": + { if (args.Length is > 1 or 0) { Alt.Log("Usage: op "); break; } - var playerOp = playerPool.FirstOrDefault(x => x.Id == int.Parse(args[0])); - if (playerOp is not IAltPlayer playerOpAlt) return; - - - if (Misc.Operators.Any(id => id == playerOpAlt.CloudID)) - { - Alt.Log($"Id {args[0]} already is an operator!"); - break; - } - - Misc.Operators.Add(playerOpAlt.CloudID); - string json = JsonSerializer.Serialize(Misc.Operators); - await File.WriteAllTextAsync(@"Operators.json", json); - - await playerOpAlt.EmitAsync("set_chat_state", true); - playerOpAlt.IsAdmin = true; + var player = (IAltPlayer)Alt.GetPlayerById(uint.Parse(args[0])); + PlayerController.Op(player, null); + Alt.Log("Given operator permissions to " + player.Serialize()); break; + } case "deop": + { if (args.Length is > 1 or 0) { Alt.Log("Usage: deop "); break; } - var playerDeOp = playerPool.FirstOrDefault(x => x.Id == int.Parse(args[0])); - if (playerDeOp is not IAltPlayer playerDeOpAlt) return; - - if (!Misc.Operators.Any(id => - id == playerDeOpAlt.CloudID)) - { - AltAsync.Log($"Id {args[0]} is not an operator!"); - break; - } - - Misc.Operators.Remove(playerDeOpAlt.CloudID); - await playerDeOpAlt.EmitAsync("set_chat_state", Misc.ChatState); - playerDeOpAlt.IsAdmin = false; + var player = (IAltPlayer)Alt.GetPlayerById(uint.Parse(args[0])); + PlayerController.Deop(player, null); + Alt.Log("Removed operator permissions from " + player.Serialize()); break; + } } } @@ -215,16 +192,13 @@ public async Task OnConsoleCommand(string name, string[] args) public async Task OnWeaponDamage(IAltPlayer player, IEntity target, uint weapon, ushort damage, Position shotOffset, BodyPart bodyPart) { + if (!player.EnableWeaponUsage) return; + if (!Misc.BlacklistedWeapons.Contains(weapon) || player is not { } damagePlayer) return; - Alt.Core.LogColored( - $"~r~ Banned Player: {damagePlayer.Name} ({damagePlayer.Id}) for using illegal weapon!"); - //Misc.BannedPlayers.Add((damagePlayer.HardwareIdHash, damagePlayer.HardwareIdExHash)); - Misc.BannedPlayers.Add(damagePlayer.CloudID); - string json = JsonSerializer.Serialize(Misc.BannedPlayers); - await File.WriteAllTextAsync(@"BannedPlayers.json", json); - - player.Kick("You're banned from this server!"); + var name = player.Serialize(); + PlayerController.Ban(player); + ChatController.BroadcastAdmins($"Banned player {name} for using illegal weapon!"); } [ScriptEvent(ScriptEventType.ColShape)] @@ -256,39 +230,19 @@ public bool OnProjectileStart(IAltPlayer player, Position startPosition, Positio return false; } - [ClientEvent("chat:message")] - public void OnChatMessage(IAltPlayer player, params string[] args) - { - var message = string.Join("", args); - if (args.Length == 0 || message.Length == 0) return; - - if (args[0].StartsWith("/")) return; - if (!Misc.ChatState && !player.IsAdmin) - { - player.SendChatMessage("{FF0000}Chat is disabled!"); - return; - } - - foreach (var p in Alt.GetAllPlayers()) - { - p.SendChatMessage( - $"{(player.IsAdmin ? "{008736}" : "{FFFFFF}")} {player.Name}({player.Id}): {{FFFFFF}}{message}"); - } - } - [ClientEvent("tp_to_waypoint")] public void TeleportToWaypoint(IAltPlayer player, int x, int y, int z) { if (!player.IsAdmin) { - player.SendChatMessage("{FF0000} No permission!"); + player.SendChatMessage(ChatConstants.NoPermissions); return; } - + if (player.IsInVehicle) player.Vehicle.Position = new Vector3(x, y, z); else player.Position = new Vector3(x, y, z); - player.SendChatMessage($"{{00FF00}} You were teleported to waypoint on {x}, {y}, {z}!"); + player.SendChatMessage(ChatConstants.SuccessPrefix + $"You were teleported to waypoint on {x}, {y}, {z}!"); } [ClientEvent("tp_to_coords")] @@ -296,7 +250,7 @@ public void TeleportToCoords(IAltPlayer player, int x, int y, int z) { if (!player.IsAdmin) { - player.SendChatMessage("{FF0000} No permission!"); + player.SendChatMessage(ChatConstants.NoPermissions); return; } diff --git a/freeroam-extended/server/freeroam-extended/Factories/PlayerFactory.cs b/freeroam-extended/server/freeroam-extended/Factories/PlayerFactory.cs index 003cfc3..1edb747 100644 --- a/freeroam-extended/server/freeroam-extended/Factories/PlayerFactory.cs +++ b/freeroam-extended/server/freeroam-extended/Factories/PlayerFactory.cs @@ -7,7 +7,7 @@ namespace Freeroam_Extended.Factories { - public partial interface IAltPlayer : IPlayer, IAsyncConvertible + public partial interface IAltPlayer : IPlayer { public IList Vehicles { get; set; } public DateTime LastVehicleSpawn { get; set; } @@ -15,14 +15,23 @@ public partial interface IAltPlayer : IPlayer, IAsyncConvertible public bool EnableWeaponUsage { get; set; } public bool DmMode { get; set; } public bool NoClip { get; set; } - public bool IsAdmin { get; set; } - public int EventCount { get; set; } + public bool IsAdmin { get; } + + public int EventCount { get; } + void ResetEventCount(); + void IncrementEventCount(); + public string CloudID { get; set; } public long OutfitHash { get; set; } public uint Sex { get; } - public Task RefreshClothes(); - public Task EquipOutfit(uint outfitHash); - public void RefreshFace(); + public PlayerData Data { get; set; } + public string Serialize(); + } + + public class PlayerData + { + public bool Operator { get; set; } + public bool Muted { get; set; } } public partial class AltPlayer : AsyncPlayer, IAltPlayer @@ -33,8 +42,9 @@ public partial class AltPlayer : AsyncPlayer, IAltPlayer public bool EnableWeaponUsage { get; set; } public bool DmMode { get; set; } public bool NoClip { get; set; } - public bool IsAdmin { get; set; } - public int EventCount { get; set; } + + public bool IsAdmin => Data.Operator; + public string CloudID { get; set; } public long OutfitHash { get; set; } public uint Sex => this.Model switch @@ -44,124 +54,30 @@ public partial class AltPlayer : AsyncPlayer, IAltPlayer _ => 2 }; - public AltPlayer(ICore server, IntPtr nativePointer, uint id) : base(server, nativePointer, id) + private int _eventCount; + public int EventCount => _eventCount; + + public void ResetEventCount() { - Vehicles = new List(); + Interlocked.Exchange(ref _eventCount, 0); } - - public void RefreshFace() + + public void IncrementEventCount() { - if (Sex == 1) - { - this.SetHeadBlendData(6, 21, 0, 6, 21, 0, 0.41f, 0.18f, 0.0f); - this.SetHeadOverlay(0, 255, 1.0f); - this.SetHeadOverlay(1, 255, 1.0f); - this.SetHeadOverlay(2, 30, 1.0f); - this.SetHeadOverlay(3, 255, 1.0f); - this.SetHeadOverlay(4, 14, 1.0f); - this.SetHeadOverlay(5, 1, 1.0f); - this.SetHeadOverlay(6, 10, 0.85f); - this.SetHeadOverlay(7, 255, 1.0f); - this.SetHeadOverlay(8, 2, 1.0f); - this.SetHeadOverlay(9, 0, 0.0f); - this.SetHeadOverlay(10, 255, 1.0f); - this.SetHeadOverlay(11, 255, 1.0f); - this.SetHeadOverlay(12, 255, 1.0f); - - this.SetHeadOverlayColor(5, 2, 11, 0); - this.SetHeadOverlayColor(8, 2, 6, 0); - - int hairs = Misc.RandomInt(1, 23); - int hairsColor = Misc.RandomInt(1, 63); - int hairsColor2 = Misc.RandomInt(1, 63); - - this.SetClothes(2, (ushort)hairs, 0, 0); - this.HairColor = (byte)hairsColor; - this.HairHighlightColor = (byte)hairsColor2; - this.SetEyeColor(2); - - float[] featureParams = { -0.78f, 0, 0, -0.07f, 0.03f, 0, 0.07f, -0.44f, 0.07f, 0.02f, -0.95f, -0.74f, -1, -0.09f, -0.57f, 0.02f, -0.1f, -0.19f, -1, -1 }; - for (int i = 0; i < featureParams.Length; i++) - { - this.SetFaceFeature((byte)i, featureParams[i]); - } - } - else if (Sex == 0) - { - this.SetHeadBlendData(2, 21, 0, 2, 21, 0, 0.5f, 0.72f, 0.0f); - this.SetHeadOverlay(0, 255, 1.0f); - this.SetHeadOverlay(1, 255, 1.0f); - this.SetHeadOverlay(2, 30, 1.0f); - this.SetHeadOverlay(3, 255, 1.0f); - this.SetHeadOverlay(4, 255, 1.0f); - this.SetHeadOverlay(5, 255, 1.0f); - this.SetHeadOverlay(6, 255, 1.0f); - this.SetHeadOverlay(7, 255, 1.0f); - this.SetHeadOverlay(8, 0, 0.15f); - this.SetHeadOverlay(9, 255, 1.0f); - this.SetHeadOverlay(10, 255, 1.0f); - this.SetHeadOverlay(11, 255, 1.0f); - this.SetHeadOverlay(12, 255, 1.0f); - - this.SetHeadOverlayColor(5, 2, 32, 0); - this.SetHeadOverlayColor(8, 2, 11, 0); - - int hairs = Misc.RandomInt(1, 22); - int hairsColor = Misc.RandomInt(1, 63); - int hairsColor2 = Misc.RandomInt(1, 63); - - this.SetClothes(2, (ushort)hairs, 0, 0); - this.HairColor = (byte)hairsColor; - this.HairHighlightColor = (byte)hairsColor2; - this.SetEyeColor(3); - - float[] featureParams = { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }; - for (int i = 0; i < featureParams.Length; i++) - { - this.SetFaceFeature((byte)i, featureParams[i]); - } - } + Interlocked.Increment(ref _eventCount); } - public async Task RefreshClothes() - { - if (!Misc.IsResourceLoaded("c_clothesfit")) - return; - - if (Sex == 2) - return; - - await ClothesFitService.DestroyPlayer(this); - await ClothesFitService.InitPlayer(this); + public PlayerData Data { get; set; } = new(); - ulong[] outfits = await ClothesFitService.GetOutfitsBySex(Sex); - - int index = Misc.RandomInt(0, outfits.Length - 1); - ulong randomElement = outfits[index]; - - await ClothesFitService.Equip(this, (uint)randomElement); + public AltPlayer(ICore server, IntPtr nativePointer, uint id) : base(server, nativePointer, id) + { + Vehicles = new List(); } - public async Task EquipOutfit(uint outfitHash) + public string Serialize() { - if (!Misc.IsResourceLoaded("c_clothesfit")) - return; - - if (Sex == 2) - return; - - await ClothesFitService.DestroyPlayer(this); - await ClothesFitService.InitPlayer(this); - - ulong[] outfits = await ClothesFitService.GetOutfitsBySex(Sex); - - if (outfits.Contains(outfitHash)) - { - await ClothesFitService.Equip(this, outfitHash); - } + return this.Name + " [" + this.Id + "]"; } - - public new IAltPlayer ToAsync(IAsyncContext _) => this; } public class AltPlayerFactory : IEntityFactory diff --git a/freeroam-extended/server/freeroam-extended/Freeroam-Extended.csproj b/freeroam-extended/server/freeroam-extended/Freeroam-Extended.csproj index 0c68f16..7eea201 100644 --- a/freeroam-extended/server/freeroam-extended/Freeroam-Extended.csproj +++ b/freeroam-extended/server/freeroam-extended/Freeroam-Extended.csproj @@ -9,8 +9,9 @@ - - + + + diff --git a/freeroam-extended/server/freeroam-extended/Main.cs b/freeroam-extended/server/freeroam-extended/Main.cs index 1dd2aac..d650add 100644 --- a/freeroam-extended/server/freeroam-extended/Main.cs +++ b/freeroam-extended/server/freeroam-extended/Main.cs @@ -1,6 +1,8 @@ -using System.Text.Json; +using System.Numerics; +using System.Text.Json; using AltV.Net; using AltV.Net.Async; +using AltV.Net.ColoredConsole; using AltV.Net.Elements.Entities; using Freeroam_Extended.Factories; using Timer = System.Timers.Timer; @@ -9,83 +11,35 @@ namespace Freeroam_Extended { public class Main : AsyncResource { - public Main() : base(true) - { - } - public override void OnStart() { - Alt.Core.LogColored("~g~ Freeroam-Extended Started!"); + ChatController.Init(); + PlayerController.Init(); + VehicleController.Init(); + VoiceController.Init(); + StatsController.Init(); + // colshape for weapon disabling everywhere but the airport Alt.CreateColShapeSphere(Misc.DMPos, Misc.DMRadius); - Voice.Init(); - - if (!File.Exists(@"BannedPlayers.json")) - { - var hashSet = new HashSet>(); - var json = JsonSerializer.Serialize(hashSet); - File.WriteAllText(@"BannedPlayers.json", json); - } - else - { - string json = File.ReadAllText(@"BannedPlayers.json") ?? ""; - - var bannedPlayers = JsonSerializer.Deserialize>(json); - - Misc.BannedPlayers = bannedPlayers ?? new HashSet(); - } - - if (!File.Exists(@"Operators.json")) - { - var hashSet = new HashSet(); - var json = JsonSerializer.Serialize(hashSet); - File.WriteAllText(@"Operators.json", json); - } - else - { - string json = File.ReadAllText(@"Operators.json") ?? ""; - - var operators = JsonSerializer.Deserialize>(json); - - Misc.Operators = operators ?? new HashSet(); - } - - if (!File.Exists("Stats.json")) - { - var json = JsonSerializer.Serialize(StatsHandler.StatsData); - File.WriteAllText("Stats.json", json); - } - else - { - var stats = JsonSerializer.Deserialize(File.ReadAllText("Stats.json")); - if (stats != null) StatsHandler.StatsData = stats; - } - if (!File.Exists("UniquePlayers.json")) - File.WriteAllText("UniquePlayers.json", JsonSerializer.Serialize(Misc.UniquePlayers)); - else - { - var uniquePlayers = JsonSerializer.Deserialize>(File.ReadAllText("UniquePlayers.json")); - if (uniquePlayers != null) Misc.UniquePlayers = uniquePlayers; - } - var fileWriteTimer = new Timer(); fileWriteTimer.Interval = 60000; fileWriteTimer.Enabled = true; fileWriteTimer.Elapsed += (sender, args) => { - StatsHandler.UpdateFile(); + StatsController.UpdateStats(); foreach (var p in Alt.GetAllPlayers()) { var player = (IAltPlayer)p; - player.EventCount = 0; + player.ResetEventCount(); } }; + Alt.LogColored(new ColoredMessage() + TextColor.Green + "Freeroam-Extended Started!"); } public override void OnStop() { - Alt.Core.LogColored("~g~ Freeroam-Extended Stopped!"); + Alt.LogColored(new ColoredMessage() + TextColor.Green + "Freeroam-Extended Stopped!"); } public override IEntityFactory GetPlayerFactory() diff --git a/freeroam-extended/server/freeroam-extended/Misc.cs b/freeroam-extended/server/freeroam-extended/Misc.cs index 89abe19..fdae845 100644 --- a/freeroam-extended/server/freeroam-extended/Misc.cs +++ b/freeroam-extended/server/freeroam-extended/Misc.cs @@ -1,5 +1,6 @@ using AltV.Net; using AltV.Net.Data; +using AltV.Net.Enums; namespace Freeroam_Extended { @@ -109,143 +110,6 @@ public static class Misc 4222310262 }; - public static HashSet BlacklistedVehicle = new () - { - 1009171724, - 1033245328, - 1036591958, - 1043222410, - 1075432268, - 1180875963, - 1181327175, - 1229411063, - 1239571361, - 1254014755, - 1336872304, - 1356124575, - 1416466158, - 1455990255, - 1483171323, - 1489874736, - 1502869817, - 1537277726, - 1542143200, - 1543134283, - 1561920505, - 1565978651, - 159274291, - 1593933419, - 1637620610, - 1653666139, - 1692272545, - 1721676810, - 1742022738, - 1897744184, - 1909700336, - 1938952078, - 1945374990, - 1949211328, - 2038858402, - 2044532910, - 2069146067, - 2071877360, - 2139203625, - 2176659152, - 219613597, - 2198148358, - 2233918197, - 2252616474, - 2306538597, - 2310691317, - 2370166601, - 2370534026, - 2403970600, - 2413121211, - 2434067162, - 2449479409, - 2482017624, - 2531412055, - 2550461639, - 2594093022, - 2600885406, - 2601952180, - 2623428164, - 2634305738, - 2694714877, - 2704629607, - 276773164, - 2816263004, - 2859440138, - 2908775872, - 2919906639, - 2920466844, - 295054921, - 3001042683, - 3013282534, - 3040635986, - 3052358707, - 3084515313, - 3147997943, - 3188846534, - 3314393930, - 3319621991, - 3493417227, - 353883353, - 3539435063, - 3545667823, - 3568198617, - 3579220348, - 3602674979, - 3606777648, - 3656405053, - 3715219435, - 373261600, - 3806844075, - 3884762073, - 3902291871, - 3903371924, - 394110044, - 3955379698, - 4018222598, - 4081974053, - 408970549, - 4180339789, - 4212341271, - 4252008158, - 4262088844, - 4262731174, - 4267640610, - 433954513, - 444994115, - 447548909, - 509498602, - 540101442, - 562680400, - 628003514, - 668439077, - 679453769, - 682434785, - 710198397, - 744705981, - 745926877, - 782665360, - 788747387, - 837858166, - 840387324, - 867467158, - 884483972, - 886810209, - 903794909, - 941494461, - 970385471, - 1058115860, - 1981688531, - 4143991942, - 368211810, - 3681241380, - 3987008919, - }; - public static readonly Position[] SpawnPositions = { new (-1734.69885f,-1108.47033f, 14.05346f ), // Pier new (-2162.94067f, -398.45275f,14.373657f), // Parking Lot at the beach-highway @@ -297,22 +161,6 @@ public static class Misc new (-675.2044f, -2378.4658f, 13.087158f), }; - public static HashSet BannedPlayers = new() - { - - }; - - public static HashSet Operators = new() - { - - }; - - public static HashSet UniquePlayers = new() - { - - }; - - public static bool ChatState = true; public static int Hour = 11; public static uint Weather = 0; diff --git a/freeroam-extended/server/freeroam-extended/StatsHandler.cs b/freeroam-extended/server/freeroam-extended/StatsHandler.cs deleted file mode 100644 index 16bdc56..0000000 --- a/freeroam-extended/server/freeroam-extended/StatsHandler.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.IO; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Freeroam_Extended -{ - public static class StatsHandler - { - public static Stats StatsData = new (); - - public static Task UpdateFile() - { - File.WriteAllText("Stats.json", JsonSerializer.Serialize(StatsData)); - return Task.CompletedTask; - } - } - - public class Stats - { - public int VehiclesSpawned { get; set; } - public int VehiclesDestroyed { get; set; } - public int PlayerDeaths { get; set; } - public int PlayerConnections { get; set; } - public int UniquePlayers { get; set; } - } -} \ No newline at end of file diff --git a/freeroam-extended/server/freeroam-extended/Voice.cs b/freeroam-extended/server/freeroam-extended/Voice.cs deleted file mode 100644 index f04c0e2..0000000 --- a/freeroam-extended/server/freeroam-extended/Voice.cs +++ /dev/null @@ -1,54 +0,0 @@ -using AltV.Net.Async; -using AltV.Net; -using AltV.Net.Elements.Entities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Freeroam_Extended -{ - static internal class Voice - { - static IVoiceChannel localChannel; - static IVoiceChannel globalChannel; - - public static void Init() - { - localChannel = Alt.CreateVoiceChannel(true, 100); - globalChannel = Alt.CreateVoiceChannel(false, 0); - } - - public static void AddPlayer(IPlayer player) - { - localChannel.AddPlayer(player); - globalChannel.AddPlayer(player); - - globalChannel.MutePlayer(player); - } - - public static void RemovePlayer(IPlayer player) - { - localChannel.RemovePlayer(player); - globalChannel.RemovePlayer(player); - - globalChannel.MutePlayer(player); - } - - public static void EnableGlobalVoice(IPlayer player) - { - globalChannel.UnmutePlayer(player); - } - - public static void DisableGlobalVoice(IPlayer player) - { - globalChannel.MutePlayer(player); - } - - public static bool IsGlobalVoiceEnabled(IPlayer player) - { - return globalChannel.IsPlayerMuted(player); - } - } -}