This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 0e770b2b49
commit 94063e4369
7342 changed files with 1718932 additions and 14 deletions

View File

@@ -0,0 +1 @@
4x1374-j382fs-599g87-31j7h3

View File

@@ -0,0 +1 @@
<put https://proxycheck.io proxy key here and remove .example from file name>

View File

@@ -0,0 +1 @@
https://discord.com/api/webhooks/832651486860541973/iYpexHJmA5E6pD6WwUT1GyvLtQ9_8ly-qB0xloIsPu7KmaU0mkQVRE_Kg0qVwGRlwhs_

View File

@@ -0,0 +1 @@
<put discord webhook URL here and remove .example from filename>

View File

@@ -0,0 +1,152 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local CAMI = CAMI
local LocalPlayer = LocalPlayer
local L = L
local SetClipboardText = SetClipboardText
local chat = chat
local net = net
local table = table
local string = string
local tonumber = tonumber
local render = render
local Color = Color
local gui = gui
local hook = hook
local surface = surface
local netstream = netstream
local ipairs = ipairs
local MsgN = MsgN
local ix = ix
local PLUGIN = PLUGIN
PLUGIN.infoIcon = ix.util.GetMaterial("icon16/information.png")
ix.option.Add("staffChat", ix.type.bool, true, {
category = "Administration",
hidden = function()
return !CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Hear Staff Chat", nil)
end
})
function PLUGIN:PopulateScoreboardPlayerMenu(client, menu)
if (CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands")) then
menu:AddOption(L("bastionCopySteamName"), function()
SetClipboardText(client:SteamName())
LocalPlayer():NotifyLocalized("bastionCopiedSteamName")
end)
menu:AddOption(L("bastionCopyCharName"), function()
SetClipboardText(client:Name())
LocalPlayer():NotifyLocalized("bastionCopiedCharName")
end)
end
if (sam and CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands") and !LocalPlayer():InVehicle() and client != LocalPlayer()) then
menu:AddOption(L("bastionGoto"), function()
if (LocalPlayer():GetMoveType() != MOVETYPE_NOCLIP) then
LocalPlayer():ConCommand("noclip")
end
LocalPlayer():ConCommand("say !goto "..client:Name())
end)
end
end
function PLUGIN:PrintTarget(target)
if (ix.option.Get("pgi")) then
SetClipboardText(target:SteamID())
end
chat.AddText(self.infoIcon, target:Name(), " (", target:SteamName(), "; ", target:SteamID(),
") | PV : ", target:Health(), " | Armure : ", target:Armor())
end
function PLUGIN:PrintStaffList(amount)
for _ = 1, amount do
local group = net.ReadString()
local members = net.ReadUInt(8)
local memberList = {}
for _ = 1, members do
memberList[#memberList + 1] = net.ReadEntity():SteamName()
end
table.sort(memberList)
chat.AddText(self.infoIcon, "[", string.utf8upper(group), "]: ", table.concat(memberList, ", "))
end
end
function PLUGIN:ShouldDisplayArea(id)
if (LocalPlayer():GetMoveType() == MOVETYPE_NOCLIP and !LocalPlayer():InVehicle()) then
return false
end
end
local commands = {
["playsound"] = 2,
["localevent"] = 2,
["showentsinradius"] = 1,
["localbroadcast"] = 2,
["localbroadcastme"] = 2,
["localbroadcastit"] = 2,
["playsong"] = 3,
["screenshake"] = 4,
["removepersistedprops"] = 1,
["removeclientprops"] = 1
}
function PLUGIN:PostDrawTranslucentRenderables(bDrawingDepth, bDrawingSkybox)
local command = string.utf8lower(ix.chat.currentCommand)
if (commands[command]) then
local range = tonumber(ix.chat.currentArguments[commands[command]])
if (range) then
render.SetColorMaterial()
render.DrawSphere(LocalPlayer():GetPos(), 0 - range, 50, 50, Color(255, 150, 0, 100))
end
end
end
net.Receive("ixOpenURL", function(len)
gui.OpenURL(net.ReadString())
end)
net.Receive("ixPlayerInfo", function(len)
PLUGIN:PrintTarget(net.ReadEntity())
end)
net.Receive("ixStaffList", function(len)
PLUGIN:PrintStaffList(net.ReadUInt(8))
end)
net.Receive("ixPlaySound", function(len)
local sound = net.ReadString()
local isGlobal = net.ReadBool()
if (hook.Run("PrePlaySound", sound, isGlobal) != false) then
surface.PlaySound(sound)
hook.Run("PostPlaySound", sound, isGlobal)
end
end)
netstream.Hook("PrintInfoList", function(list)
for _, v in ipairs(list) do
MsgN(v)
end
end)
function PLUGIN:OnPlayerChat()
if (ix.config.Get("suppressOnPlayerChat", true)) then
return true
end
end

View File

@@ -0,0 +1,137 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if (SERVER) then
util.AddNetworkString("ixBindGrab")
util.AddNetworkString("ixBindGrabList")
end
CAMI.RegisterPrivilege({
Name = "Helix - Check Bind",
MinAccess = "superadmin"
})
ix.command.Add("PlyGetBinds", {
description = "Get a list of all of someone's binds.",
privilege = "Check Bind",
arguments = {ix.type.player, bit.bor(ix.type.optional, ix.type.bool)},
OnRun = function(self, client, target, all)
if (IsValid(target.ixBindGrab) and target.ixBindGrabTime and target.ixBindGrabTime > CurTime()) then
return "Someone else is checking this player's binds already. Please wait a few seconds!"
end
target.ixBindGrab = client
target.ixBindGrabTime = CurTime() + 5
target.ixBindGrabAll = all
net.Start("ixBindGrab")
net.Send(target)
end,
bNoIndicator = true
})
if (CLIENT) then
net.Receive("ixBindGrab", function()
net.Start("ixBindGrab")
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(input.LookupKeyBinding(i) or "", 255))
end
net.SendToServer()
end)
local blacklist = {
["slot0"] = true,
["slot1"] = true,
["slot2"] = true,
["slot3"] = true,
["slot4"] = true,
["slot5"] = true,
["slot6"] = true,
["slot7"] = true,
["slot8"] = true,
["slot9"] = true,
["+zoom"] = true,
["+forward"] = true,
["+back"] = true,
["+moveleft"] = true,
["+moveright"] = true,
["+jump"] = true,
["+speed"] = true,
["+walk"] = true,
["+duck"] = true,
["+lookup"] = true,
["+left"] = true,
["+lookdown"] = true,
["+right"] = true,
["+attack"] = true,
["+attack2"] = true,
["+reload"] = true,
["+use"] = true,
["invprev"] = true,
["invnext"] = true,
["+menu"] = true,
["+menu_context"] = true,
["gmod_undo"] = true,
["+showscores"] = true,
["gm_showhelp"] = true,
["gm_showteam"] = true,
["gm_showspare1"] = true,
["gm_showspare2"] = true,
["noclip"] = true,
["messagemode"] = true,
["toggleconsole"] = true,
["cancelselect"] = true,
["pause"] = true,
["save quick"] = true,
["load quick"] = true,
["impulse 100"] = true,
["+voicerecord"] = true,
["jpeg"] = true,
}
net.Receive("ixBindGrabList", function()
local all = net.ReadBool()
MsgN(net.ReadString().."'s binds ("..net.ReadString()..")")
for i = 1, BUTTON_CODE_LAST do
local bind = net.ReadString()
if (!all and blacklist[bind]) then continue end
if (bind and bind != "") then
if (#bind == 255) then
bind = bind.."..."
end
MsgN((input.GetKeyName(i) or i)..": ", bind)
end
end
LocalPlayer():Notify("Binds were printed in console!")
end)
else
net.Receive("ixBindGrab", function(len, client)
if (!IsValid(client.ixBindGrab) or !CAMI.PlayerHasAccess(client.ixBindGrab, "Helix - Check Bind")) then return end
net.Start("ixBindGrabList")
net.WriteBool(client.ixBindGrabAll)
net.WriteString(client:SteamName())
net.WriteString(client:SteamID())
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(net.ReadString(), 255))
end
net.Send(client.ixBindGrab)
client.ixBindGrab = nil
end)
end

View File

@@ -0,0 +1,507 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local pcall = pcall
local util = util
local ix = ix
local string = string
local net = net
local ipairs = ipairs
local IsValid = IsValid
local os = os
local L = L
local math = math
local table = table
local pairs = pairs
local print = print
local CHTTP = CHTTP
local player = player
local CAMI = CAMI
if (!CHTTP) then
pcall(require, "chttp")
end
local PLUGIN = PLUGIN
PLUGIN.TYPE_UNKNOWN = 1
PLUGIN.TYPE_KNOWN = 2
local COOKIE_KEY = "qvFT4QSSST8K4tZF"
local fileChecks = {
{"hl2_misc_001.vpk", "hl2"},
{"ep2_pak_008.vpk", "ep2"},
{"cstrike_pak_003.vpk", "css", "cstrike"},
{"bin/client_panorama.dll", "csgo"},
{"detail.vbsp", "gmod", "garrysmod"}
}
util.AddNetworkString("RecieveDupe")
ix.util.Include("sv_antialt_db.lua")
ix.lang.AddTable("english", {
altSignupProxy = "Vous essayez de rejoindre Willard Networks en tant que nouvel utilisateur tout en utilisant un proxy ou un VPN. Pour lutter contre les autres comptes, nous ne l'autorisons pas.\n\nVeuillez désactiver votre proxy/VPN et rejoindre le serveur. Après avoir rejoint le serveur avec succès une fois, vous pouvez réactiver votre proxy/VPN pour de futures visites.\n\nSi vous n'utilisez pas de proxy ou de VPN, veuillez contacter un membre de l'équipe du STAFF sur nos forums ou discord"
})
ix.log.AddType("altNewClient", function(client)
return string.format("[AltChecker] %s rejoint pour la première fois.", client:SteamName())
end)
ix.log.AddType("altKnownNewCookie", function(client)
return string.format("[AltChecker] %s rejoint avec une installation inconnue.", client:SteamName())
end)
ix.log.AddType("altKnownCookieMatched", function(client, matched, total)
return string.format("[AltChecker] %s rejoint sans cookie, mais l'installation correspond au cookie existant. %d/%d", client:SteamName(), matched, total)
end)
hook.Add("PlayerInitialSpawn", "bastionAntiAlt", function(client)
if (client:IsBot()) then return end
client.ixAltData = {
checks = 4 + #fileChecks,
altLogging = 0,
error = false,
received = false,
checkComplete = false,
newAltFound = false,
mode = 0,
localCookie = "",
cookies = false,
ip = false,
timestamps = false,
otherCookies = {},
otherIPs = {},
otherTimestamps = {},
otherTimestampsNZ = {},
otherTimeMatches = {},
discordAlert = {
cookies = {},
timestamps = {},
ips = {},
altIDs = {}
}
}
-- Lookup user data
PLUGIN:AltLoadUserData(client)
if (PLUGIN.API_KEY) then
-- Lookup user IP
PLUGIN:AltLookupIP(client)
else
client.ixAltData.checkes = client.ixAltData.checks - 1
end
-- Check for IP matches
PLUGIN:AltLookupIPMatches(client)
-- Request cookie and install timestamps
PLUGIN:RequestClientData(client)
end)
function PLUGIN:RequestClientData(client)
net.Start("RecieveDupe")
net.WriteUInt(1, 3)
net.WriteString(COOKIE_KEY)
for _, v in ipairs(fileChecks) do
net.WriteString(v[1])
net.WriteString(v[3] or v[2])
end
net.Send(client)
end
net.Receive("RecieveDupe", function(len, client)
if (!IsValid(client) or !client.ixAltData or client.ixAltData.received) then return end
local data = client.ixAltData
data.received = true
-- set cookie
data.localCookie = net.ReadString()
-- set file timestamps
data.timestamps = {}
for i = 1, #fileChecks do
data.timestamps[i] = net.ReadUInt(32)
end
-- Check for cookie matches
if (data.localCookie != "") then
PLUGIN:AltLookupCookieMatches(client, data)
else
PLUGIN:AltPreFinalChecking(client)
end
-- Check for install timestamp matches
data.otherTimestamps = {}
data.otherTimestampsNZ = {}
for i = 1, #fileChecks do
PLUGIN:AltLookupTimestampMatches(client, data, fileChecks[i][2], data.timestamps[i])
end
end)
function PLUGIN:AltPreFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
-- if we errored, don't do anything
-- check will be reexecuted when the client rejoins
if (data.error) then return end
-- check if all queries finished
data.checks = data.checks - 1
if (data.checks != 0) then return end
-- cookie matches (STRONG)
if (#data.otherCookies > 0) then
for _, v in ipairs(data.otherCookies) do
self:AltFound(client, v[2], "cookie", "cookie")
data.discordAlert.cookies[#data.discordAlert.cookies + 1] = (v[2] or "").." ("..(v[1] or "")..")"
data.discordAlert.altIDs[v[2]] = true
end
end
-- IP (WEAK)
if (#data.otherIPs > 0) then
for _, v in ipairs(data.otherIPs) do
data.discordAlert.ips[#data.discordAlert.ips + 1] = v[2]
data.discordAlert.altIDs[v[2]] = true
end
end
-- time matches (STRONG-MEDIUM)
self:AggregateTimestampMatches(data)
-- If no local cookie and player is known, check if a known cookie was time-matched
if (data.localCookie == "" and data.mode == self.TYPE_KNOWN) then
self:FindMatchingCookie(client, data)
end
if (#data.otherTimeMatches > 0) then
-- go looking for the other clients that own our matched timestamps
self:AltLookupCookieForTimestamps(client, data, #fileChecks)
else
-- else we don't need to wait for the lookup above
data.checkComplete = true
self:AltFinalChecking(client)
end
end
function PLUGIN:AltFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
if (!data.checkComplete or data.altLogging != 0) then return end
self:DiscordAlert(client)
-- update IP list
local steamID = client:SteamID64()
local ip = self.GetIPAddress(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("steamid", steamID)
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0) then
local query2 = mysql:Insert("bastion_antialt_userips")
query2:Insert("steamid", steamID)
query2:Insert("ip", ip)
query2:Insert("last_seen", os.time())
query2:Execute()
else
local query2 = mysql:Update("bastion_antialt_userips")
query2:Where("id", result[1].id)
query2:Update("last_seen", os.time())
query2:Execute()
end
end)
query:Execute()
-- Kick if new player on proxy/vpn
if (data.mode == self.TYPE_UNKNOWN) then
if (self.API_KEY and (data.ip.proxy == "yes" or (data.ip.risk or 0) > 60)) then
if (ix.config.Get("VPNKick")) then
self:ProxyAlert(client)
client:Kick(L("altSignupProxy", client))
else
if (!self:NotifyProxyJoin(client) or ix.config.Get("ProxyAlwaysAlert")) then
self:ProxyAlert(client)
end
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altKnownNewCookie")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
if (sam) then
timer.Simple(3, function()
if (!IsValid(client)) then return end
local query1 = mysql:Select("bastion_antialt_alts")
query1:Where("steamid", client:SteamID64())
query1:Select("alt_id")
query1:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then return end
local query2 = mysql:Select("bastion_antialt_alts")
query2:Where("alt_id", result[1].alt_id)
query2:WhereNotEqual("steamid", client:SteamID64())
query2:Select("steamid")
query2:Callback(function(result2)
if (!IsValid(client)) then return end
if (!result2 or #result2 == 0) then return end
for k, v in ipairs(result2) do
sam.player.is_banned(util.SteamIDFrom64(v.steamid), function(banned)
if (!banned or !IsValid(client)) then return end
client:Kick("You have a banned alt account.")
return
end)
end
end)
query2:Execute()
end)
query1:Execute()
end)
end
end
--[[
COOKIE STUFF
]]
function PLUGIN:WhitelistPlayer(client)
local data = client.ixAltData
if (!data) then return end
if (data.localCookie) then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
return true
end
end
function PLUGIN.RandomString()
local result = {} -- The empty table we start with
while (#result != 64) do
local char = string.char(math.random(32, 126))
if (string.find(char, "%w")) then
result[#result + 1] = char
end
end
return table.concat(result)
end
function PLUGIN:GenerateCookie(client, data)
local cookie = self.RandomString()
self:UpdateLocalCookie(client, data, cookie)
local query = mysql:Insert("bastion_antialt_users")
query:Insert("steamid", client:SteamID64())
query:Insert("steam_name", client:SteamName())
query:Insert("cookie", cookie)
query:Execute()
end
function PLUGIN:UpdateLocalCookie(client, data, cookie)
data.localCookie = cookie
net.Start("RecieveDupe")
net.WriteUInt(2, 3)
net.WriteString(COOKIE_KEY)
net.WriteString(cookie)
net.Send(client)
self:StoreCookieInfo(data, fileChecks)
end
function PLUGIN:FindMatchingCookie(client, data)
for _, v in ipairs(data.otherTimeMatches) do
for _, v1 in ipairs(data.cookies) do
if (v1.cookie == v[1]) then
-- found a timestamp match belonging to the client, restore cookie
-- in case of e.g. gmod reinstall
ix.log.Add(client, "altKnownCookieMatched", v[2], #fileChecks)
self:UpdateLocalCookie(client, data, v[1])
return
end
end
end
end
--[[
LOGGING AND ALERTING
]]
local ALT_OFFSET = 0
function PLUGIN:AltFound(client, steamid, type, info)
local ids = {client:SteamID64(), steamid}
local data = client.ixAltData
data.altLogging = data.altLogging + 1
local query = mysql:Select("bastion_antialt_alts")
query:WhereIn("steamid", ids)
query:Callback(function(result)
if (!result or #result == 0) then
local alt_id = os.time() + ALT_OFFSET
ALT_OFFSET = ALT_OFFSET + 1
local text = table.concat(ids,"+")..": "..info.." (alt-id: "..alt_id..")"
self:InsertNewAlt(ids[1], alt_id, type, text)
self:InsertNewAlt(steamid, alt_id, type, text)
data.newAltFound = true
elseif (#result == 1) then
self:InsertNewAlt(
result[1].steamid == steamid and ids[1] or steamid,
result[1].alt_id,
type,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
elseif (result[2].alt_id != result[1].alt_id) then
self:MergeAlts(
result[2].alt_id,
result[1].alt_id,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
end
data.altLogging = data.altLogging - 1
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:DiscordAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local data = client.ixAltData
if (!data.newAltFound) then return end
local tbl = {
embeds = {{
title = "Alt found for "..client:SteamName(),
description = "An alt account match was found for **"..client:SteamName().."** (*"..client:SteamID64().."*)\n\n__COOKIE__: 99.99% certainty via installed cookie\nShown as 'SteamID64 (SteamName)'\n__TIMESTAMP__: check via installation date/time or absense of mounted games (hl2,ep2,css,csgo,gmod)\nMore matches = more certainty, especially if all/most are installed\nShown as 'SteamID64 (SteamName; date/time matches - installed matches)'\n__IP__: users that connected from the same IP address at any point\nShown as 'SteamID64'",
color = 13632027,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
},
fields = {
}
}}
}
if (data.discordAlert.cookies and #data.discordAlert.cookies > 0) then
table.insert(tbl.embeds[1].fields, {name = "COOKIE", value = table.concat(data.discordAlert.cookies, "\n")})
end
if (data.discordAlert.timestamps and #data.discordAlert.timestamps > 0) then
table.insert(tbl.embeds[1].fields, {name = "TIMESTAMP", value = table.concat(data.discordAlert.timestamps, "\n")})
end
if (data.discordAlert.ips and #data.discordAlert.ips > 0) then
table.insert(tbl.embeds[1].fields, {
name = "IP",
value = string.format("Address: [%s](https://proxycheck.io/threats/%s)\n", data.ipAddress, data.ipAddress)..
table.concat(data.discordAlert.ips, "\n")
})
end
local ipLinks = {"["..client:SteamID64().."](https://steamidfinder.com/lookup/"..client:SteamID64().."/)"}
for k in pairs(data.discordAlert.altIDs) do
ipLinks[#ipLinks + 1] = "["..k.."](https://steamidfinder.com/lookup/"..k.."/)"
end
table.insert(tbl.embeds[1].fields, {
name = "SteamID Finder Links",
value = table.concat(ipLinks,"\n")
})
for _, field in ipairs(tbl.embeds[1].fields) do
if (string.len(field.value) > 1024) then
field.value = string.sub(field.value, 1, 1024)
end
end
local request = {
failed = function(error) print("discord error", error) end,
success = function(code, body, headers)
if (code != 200) then print("discord error", code, body) end
end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:ProxyAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local ip, steamID = client.ixAltData.ipAddress, client:SteamID64()
local tbl = {
embeds = {{
title = "New player using VPN - "..client:SteamName(),
description = client:SteamName().." joined WN for the first time, but was using a proxy/VPN. They have been kicked.\n\n"..
string.format("More info: [%s](https://proxycheck.io/threats/%s) & [%s](https://steamidfinder.com/lookup/%s/)", ip, ip, steamID, steamID),
color = 16312092,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
}
}}
}
local request = {
failed = function(error) print("discord error", error) end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:NotifyProxyJoin(client)
local bSend = false
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Proxy Notify")) then
bSend = true
v:NotifyLocalized("bastionProxyNotify", client:SteamName())
end
end
return bSend
end

View File

@@ -0,0 +1,461 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local IsValid = IsValid
local string = string
local os = os
local print = print
local util = util
local CHTTP = CHTTP
local ipairs = ipairs
local table = table
local pairs = pairs
local netstream = netstream
local SortedPairsByMemberValue = SortedPairsByMemberValue
local PLUGIN = PLUGIN
local MAX_CACHE_AGE = 7 * 24 * 3600 -- 7 days
PLUGIN.ipCache = {}
hook.Add("DatabaseConnected", "bastionAntiAlt", function()
local query = mysql:Create("bastion_antialt_users")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(128) NOT NULL")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_cookies")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:Create("ts_hl2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_ep2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_css", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_csgo", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_gmod", "INT(11) UNSIGNED DEFAULT NULL")
query:PrimaryKey("cookie")
query:Execute()
query = mysql:Create("bastion_antialt_userips")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("last_seen", "INT(11) UNSIGNED NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_ip")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("updated", "INT(11) UNSIGNED NOT NULL")
query:Create("asn", "VARCHAR(12) NOT NULL")
query:Create("provider", "VARCHAR(128) NOT NULL")
query:Create("isocode", "VARCHAR(2) NOT NULL")
query:Create("proxy", "TINYINT(1) UNSIGNED DEFAULT 0")
query:Create("type", "VARCHAR(32) NOT NULL")
query:Create("risk", "INT UNSIGNED NOT NULL")
query:Create("attack_count", "INT UNSIGNED DEFAULT NULL")
query:Create("attack_history", "TEXT DEFAULT NULL")
query:PrimaryKey("ip")
query:Execute()
query = mysql:Create("bastion_antialt_alts")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("alt_id", "INT UNSIGNED NOT NULL")
query:Create("type", "VARCHAR(10) NOT NULL")
query:Create("info", "TEXT NOT NULL")
query:PrimaryKey("steamid")
query:Execute()
end)
function PLUGIN:AltLoadUserData(client)
local query = mysql:Select("bastion_antialt_users")
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client.ixAltData.mode = self.TYPE_UNKNOWN
else
client.ixAltData.mode = self.TYPE_KNOWN
client.ixAltData.cookies = result
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN.GetIPAddress(client)
local ip = client:IPAddress()
return string.gsub(ip, ":%d+$", "", 1)
end
function PLUGIN:AltLookupIP(client)
local ip = self.GetIPAddress(client)
client.ixAltData.ipAddress = ip
if (self.ipCache[ip]) then
-- ip address still in cache
client.ixAltData.ip = self.ipCache[ip]
self:AltPreFinalChecking(client)
else
-- lookup address
local query = mysql:Select("bastion_antialt_ip")
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0 or (result[1].updated < (os.time() - MAX_CACHE_AGE))) then
self:AltFetchIP(client, ip, !result or #result == 0)
else
-- load in data from the DB
if (result[1].proxy == 1) then
result[1].proxy = "yes"
else
result[1].proxy = "no"
end
client.ixAltData.ip = result[1]
self:AltPreFinalChecking(client)
end
end)
query:Execute()
end
end
function PLUGIN:AltFetchIP(client, ip, bCreateNew)
-- address not found or record too old, look it up
local url = string.format("https://proxycheck.io/v2/%s?key=%s&vpn=1&asn=1&risk=1", ip, self.API_KEY)
local request = {
failed = function(error)
-- error stop matching
print("[BASTION] Alt check IP API call failed with error: "..error)
print("[BASTION] Client: "..client:SteamName().."; ip: "..ip)
client.ixAltData.error = true
end,
success = function(code, body, headers)
if (!IsValid(client)) then return end
local httpResult = util.JSONToTable(body)
if (!httpResult) then
-- error stop matching
print("[BASTION] Alt check IP API call failed to parse httpResult.")
client.ixAltData.error = true
return
end
local status = httpResult.status
if (status == "denied" or status == "error" or status == "warning") then
print("[BASTION] Alt check IP API call failed. Status: "..status.."; Message: "..(httpResult.message or "no message").."\n")
if (status != "warning") then
-- error stop matching
client.ixAltData.error = true
return
end
end
-- we got the data
local lookup = httpResult[ip]
self:StoreIPLookup(ip, lookup, bCreateNew)
client.ixAltData.ip = lookup
self:AltPreFinalChecking(client)
end,
url = url,
method = "GET"
}
CHTTP(request)
end
function PLUGIN:AltLookupCookieMatches(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
-- we found other cookies
if (result and #result > 0) then
for k, v in ipairs(result) do
data.otherCookies[k] = {v.steam_name, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupIPMatches(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("ip", PLUGIN.GetIPAddress(client))
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for k, v in ipairs(result) do
client.ixAltData.otherIPs[k] = {v.ip, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupTimestampMatches(client, data, game, timestamp)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("ts_"..game, timestamp)
if (data.localCookie != "") then
-- not interested in timestamps that we know for this client
query:WhereNotEqual("cookie", data.localCookie)
end
query:Callback(function(result)
if (result and #result > 0) then
for _, v in ipairs(result) do
data.otherTimestamps[v.cookie] = data.otherTimestamps[v.cookie] or {}
table.insert(data.otherTimestamps[v.cookie], game)
-- track timestamp matches
-- non-zero timestamps are worth a lot more, so tracked separately too
if (timestamp != 0) then
data.otherTimestampsNZ[v.cookie] = data.otherTimestampsNZ[v.cookie] or {}
data.otherTimestampsNZ[v.cookie][game] = true
end
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AggregateTimestampMatches(data)
data.otherTimeMatches = {}
for cookie, matches in pairs(data.otherTimestamps) do
if (#matches == 1) then continue end
data.otherTimeMatches[#data.otherTimeMatches + 1] = {cookie, #matches}
end
table.SortByMember(data.otherTimeMatches, 2, false)
end
function PLUGIN:AltLookupCookieForTimestamps(client, data, maxMatches)
local cookies = {}
for cookie, matches in pairs(data.otherTimestamps) do
-- only find cookies if at least 2 matches of which one is non-zero
if (#matches >= 2 and data.otherTimestampsNZ[cookie]) then
cookies[#cookies + 1] = cookie
end
end
if (#cookies == 0) then
data.checkComplete = true
self:AltFinalChecking(client)
return
end
local query = mysql:Select("bastion_antialt_users")
query:WhereNotEqual("steamid", client:SteamID64())
query:WhereIn("cookie", cookies)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for _, v in ipairs(result) do
local installed = table.GetKeys(data.otherTimestampsNZ[v.cookie])
local text = string.format("%d/%d matches - installed: %s)",
#data.otherTimestamps[v.cookie],
maxMatches,
table.concat(installed, "+")
)
self:AltFound(client, v.steamid, "timestamp", text)
data.discordAlert.timestamps[# data.discordAlert.timestamps + 1] = v.steamid.." ("..v.steam_name.."; "..text..")"
data.discordAlert.altIDs[v.steamid] = true
end
end
data.checkComplete = true
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:StoreCookieInfo(data, fileChecks)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("cookie", data.localCookie)
query:Callback(function(result)
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_cookies")
queryInsert:Insert("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryInsert:Insert("ts_"..v[2], data.timestamps[k])
end
queryInsert:Execute()
else
local queryUpdate = mysql:Update("bastion_antialt_cookies")
queryUpdate:Where("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryUpdate:Update("ts_"..v[2], data.timestamps[k])
end
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreClientCookie(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_users")
queryInsert:Insert("steamid", client:SteamID64())
queryInsert:Insert("steam_name", client:SteamName())
queryInsert:Insert("cookie", data.localCookie)
queryInsert:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreIPLookup(ip, httpResult, bNewEntry)
if (!bNewEntry) then
local query = mysql:Update("bastion_antialt_ip")
query:Where("ip", ip)
query:Update("updated", os.time())
query:Update("asn", httpResult.asn)
query:Update("provider", httpResult.provider)
query:Update("isocode", httpResult.isocode)
query:Update("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Update("type", httpResult.type)
query:Update("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Update("attack_count", httpResult["attack history"].Total)
query:Update("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
else
local query = mysql:Insert("bastion_antialt_ip")
query:Insert("ip", ip)
query:Insert("updated", os.time())
query:Insert("asn", httpResult.asn)
query:Insert("provider", httpResult.provider)
query:Insert("isocode", httpResult.isocode)
query:Insert("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Insert("type", httpResult.type)
query:Insert("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Insert("attack_count", httpResult["attack history"].Total)
query:Insert("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
end
end
function PLUGIN:InsertNewAlt(steamid, alt_id, type, text)
local query = mysql:Insert("bastion_antialt_alts")
query:Insert("steamid", steamid)
query:Insert("alt_id", alt_id)
query:Insert("type", type)
query:Insert("info", text)
query:Execute()
end
function PLUGIN:MergeAlts(old_id, new_id, text)
local query = mysql:Select("bastion_antialt_alts")
query:Where("alt_id", old_id)
query:Callback(function(result2)
for _, v in ipairs(result2) do
local queryUpdate = mysql:Update("bastion_antialt_alts")
queryUpdate:Where("steamid", v.steamid)
queryUpdate:Update("alt_id", new_id)
queryUpdate:Update("info", v.info.." - "..text)
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:LookupSteamID(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64()
end
local query = mysql:Select("bastion_antialt_alts")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local querySelect = mysql:Select("bastion_antialt_alts")
querySelect:Where("alt_id", result[1].alt_id)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
local toReturn = {"Alts for "..steamid..":", "(SteamID64) - (detection trigger type) - (info)"}
for _, v in ipairs(finalResult) do
toReturn[#toReturn + 1] = v.steamid.." - "..v.type.." - info: "..v.info
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end
function PLUGIN:LookupIPUsers(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64(steamid)
end
local query = mysql:query("bastion_antialt_userips")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local list = {}
for k, v in ipairs(result) do
list[k] = v.ip
end
local querySelect = mysql:query("bastion_antialt_userips")
querySelect:WhereIn("ip", list)
querySelect:WhereNotEqual("steamid", steamid)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local toReturn = {"Other users on same IP as "..steamid, "(SteamID64) - (ip) - (last seen on this ip)"}
for _, v in SortedPairsByMemberValue(finalResult, "steamid") do
toReturn[#toReturn + 1] = v.steamid.." - "..v.ip.." - "..os.date("%Y-%m-%d", v.last_seen)
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end

View File

@@ -0,0 +1,96 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook = hook
local ix = ix
local util = util
local PLUGIN = PLUGIN
PLUGIN.permaBan = {
-- Crazyman (~Atle/Gr4Ss), code stealing
["STEAM_0:1:120921609"] = true,
["2.73.226.221"] = true,
["2.72.176.41"] = true,
["2.132.96.235"] = true,
["2.132.103.122"] = true,
["2.132.147.172"] = true,
["2.132.150.162"] = true,
["95.57.132.81"] = true,
-- carlsmei (~Atle/Gr4Ss), code stealing
["STEAM_0:0:216726444"] = true,
-- Schwarz Kruppzo (~Atle/Gr4Ss), code stealing
["STEAM_0:1:44629398"] = true,
-- KoC (~Atle/Gr4Ss), toxic, ban evasion
["76561198017957016"] = true,
["76561199123547331"] = true,
["73.121.218.83"] = true,
["136.144.43.116"] = true,
["136.144.43.63"] = true,
-- Kalingi (Staff vote, Hiros/Gr4Ss), toxic, threatening hacks & blackmail
["76561198066620287"] = true,
["STEAM_0:1:53177279"] = true,
["24.197.171.2"] = true,
-- Brando (~Atle/Gr4Ss), pedo
["STEAM_0:1:54660756"] = true,
-- Walter (~Atle/Gr4Ss), none
["STEAM_0:1:43085888"] = true,
-- PrplSckz/The Enemy (~Rad/Gr4Ss), forum DDoS
["STEAM_0:1:68538156"] = true,
-- Hackers (~Gr4Ss)
["STEAM_0:1:13809165"] = true,
["STEAM_0:1:4916602"] = true,
["STEAM_0:1:517232907"] = true,
["STEAM_0:1:17046093"] = true,
-- Exploiters
["STEAM_0:0:549109050"] = true,
["76561199131288084"] = true,
["76561199087140341"] = true,
["76561199206105794"] = true,
["76561198874018211"] = true,
["109.252.109.68"] = true,
["76561199121843993"] = true,
-- Zeroday / Newport Gaming - Sketchy dude + some hacking & exploiting (~M!NT/RAD)
["172.82.32.147"] = true,
["76561199441966033"] = true,
-- Cazo
["82.0.106.136"] = true,
["76561199150421701"] = true,
-- lqut (Translating ISIS Propaganda) (~M!NT/RAD)
["STEAM_0:0:173208852"] = true,
["5.30.219.71"] = true,
["76561198306683432"] = true,
-- madbluntz (doxxing, minging, ddosing, etc etc) (~M!NT)
["176.117.229.107"] = true,
["176.117.229.107"] = true,
["178.214.250.178"] = true,
["46.191.232.69"] = true,
["178.168.94.11"] = true,
["163.182.82.195"] = true,
["104.231.185.125"] = true,
["STEAM_0:0:763201893"] = true,
["STEAM_0:0:629741416"] = true,
["STEAM_0:1:764405213"] = true,
["STEAM_0:1:817531224"] = true,
["STEAM_0:0:785033797"] = true,
["STEAM_0:1:421783352"] = true,
["STEAM_0:1:78544439"] = true,
["STEAM_0:1:178702634"] = true,
["STEAM_0:0:627119036"] = true,
["STEAM_0:0:585787645"] = true,
["STEAM_0:1:43085888"] = true,
}
hook.Add("CheckPassword", "bastionBanList", function(steamid, networkid)
if (PLUGIN.permaBan[steamid] or PLUGIN.permaBan[util.SteamIDFrom64(steamid)] or PLUGIN.permaBan[networkid]) then
ix.log.AddRaw("[BANS] "..steamid.." ("..networkid..") a essayé de se connecter mais est strictement interdit.")
return false
end
end)

View File

@@ -0,0 +1,211 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook_Add = hook.Add
local timer_Create = timer.Create
local os_time = os.time
local pairs = pairs
local net_ReadHeader = net.ReadHeader
local util_NetworkIDToString = util.NetworkIDToString
local ix = ix
local IsValid = IsValid
local string_len = string.len
local string_sub = string.sub
-- Code inspired by:
-- Gmod Net Library Debug
-- https://github.com/HexaneNetworks/gmod-netlibrary-debug
-- v2.3
-- October 2020
local PLUGIN = PLUGIN
hook_Add("DatabaseConnected", "bastionNetDB", function()
local query = mysql:Create("bastion_netlog")
query:Create("id", "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("length", "INT UNSIGNED NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("args", "VARCHAR(200) DEFAULT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_netspam")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("type", "BOOL NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(50) NOT NULL")
query:Create("ip", "VARCHAR(25) NOT NULL")
query:Create("time", "INT NOT NULL")
query:PrimaryKey("id")
query:Execute()
end)
local netSpamCount = {}
local netFlagged = {}
local comSpamCount = {}
local comFlagged = {}
local threshold = 20
timer_Create("ixBastionNetSpam.Clear", 1.1, 0, function()
local time = os_time()
for steamID, data in pairs(netFlagged) do
for name in pairs(data.names) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 0)
query:Insert("count", netSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
netSpamCount = {}
netFlagged = {}
for steamID, data in pairs(comFlagged) do
for name in pairs(data.commands) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 1)
query:Insert("count", comSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
comSpamCount = {}
comFlagged = {}
end)
local netIgnoreList = {
["76561198002319953"] = 2
}
local netSpamAmount = {
["NetStreamDS"] = 20,
["76561198002319953"] = 30
}
function net.Incoming(len, client)
local i = net_ReadHeader()
local name = util_NetworkIDToString(i)
if (!name) then return end
local func = net.Receivers[name:lower()]
if (!func) then return end
--
-- len includes the 16 bit int which told us the message name
--
len = len - 16
if (ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
netSpamCount[steamID] = netSpamCount[steamID] or {}
netSpamCount[steamID][name] = (netSpamCount[steamID][name] or 0) + 1
if (netSpamCount[steamID][name] > (netSpamAmount[name] or threshold)) then
if (!netFlagged[steamID]) then
netFlagged[steamID] = {
names = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
netFlagged[steamID].names[name] = true
end
if (ix.config.Get("netLoggingEnabled") and (!netIgnoreList[name] or netIgnoreList[name] < netSpamCount[steamID][name])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
func(len, client)
end
local conSpamAmount = {
}
local conIgnoreList = {
}
PLUGIN.oldRun = PLUGIN.oldRun or concommand.Run
function concommand.Run(client, command, args, argString)
if (IsValid(client) and command and ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
comSpamCount[steamID] = comSpamCount[steamID] or {}
comSpamCount[steamID][command] = (comSpamCount[steamID][command] or 0) + 1
if (comSpamCount[steamID][command] > (conSpamAmount[command] or threshold)) then
if (!comFlagged[steamID]) then
comFlagged[steamID] = {
commands = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", netSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
comFlagged[steamID].commands[command] = true
end
if (ix.config.Get("netLoggingEnabled") and (!conIgnoreList[command] or conIgnoreList[command] < comSpamCount[steamID][command])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", comSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
return PLUGIN.oldRun(client, command, args, argString)
end

View File

@@ -0,0 +1,100 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
--Made by Liquid
PLUGIN.MIN_PLAYER_COUNT = 30
PLUGIN.STOP_AFTER_CONNECTED_FOR = 600
PLUGIN.MIN_SIZE = 100
PLUGIN.TRACE_SIZE = 1000
ORIGINAL_NET = ORIGINAL_NET or table.Copy(net)
local _net = ORIGINAL_NET
local IsValid = IsValid
local currentMessageName
hook.Add("DatabaseConnected", "bastionNetSizeLog", function()
local query = mysql:Create("bastion_netsizelog")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("timestamp", "INT(11) UNSIGNED NOT NULL")
query:Create("realtime", "FLOAT NOT NULL")
query:Create("message_name", "VARCHAR(128) NOT NULL")
query:Create("size", "INT(11) UNSIGNED NOT NULL")
query:Create("stack_trace", "TEXT DEFAULT NULL")
query:PrimaryKey("id")
query:Callback(function()
local delete = mysql:Delete("bastion_netsizelog")
delete:WhereLT("timestamp", os.time() - 3 * 24 * 3600)
delete:Execute()
end)
query:Execute()
end)
local function netLog(players)
local count = player.GetCount()
if (count > 1 and count <= PLUGIN.MIN_PLAYER_COUNT) then return end
if (type(players) == "Player") then
players = {players}
elseif (type(players) == "CRecipientFilter") then
players = players:GetPlayers()
end
local size = _net.BytesWritten()
if (size <= PLUGIN.MIN_SIZE) then return end
for k, v in ipairs(players) do
if (!IsValid(v)) then continue end
if (v.ixStopNetLog or v:TimeConnected() > PLUGIN.STOP_AFTER_CONNECTED_FOR) then
v.ixStopNetLog = true
continue
end
local query = mysql:Insert("bastion_netsizelog")
query:Insert("steamid", v:SteamID64())
query:Insert("timestamp", os.time())
query:Insert("realtime", RealTime())
query:Insert("message_name", currentMessageName)
query:Insert("size", size)
if (size >= PLUGIN.TRACE_SIZE or currentMessageName == "NetStreamDS") then
query:Insert("stack_trace", debug.traceback())
end
query:Execute()
end
end
net.Start = function(name, unreliable)
currentMessageName = name
return _net.Start(name, unreliable)
end
net.Send = function(players)
netLog(players)
currentMessageName = nil
return _net.Send(players)
end
net.SendOmit = function(players)
netLog(players)
currentMessageName = nil
return _net.SendOmit(players)
end
net.Broadcast = function(pos)
netLog(player.GetAll())
currentMessageName = nil
return _net.Broadcast()
end

View File

@@ -0,0 +1,190 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local ix = ix
local Color = Color
local chat = chat
local string = string
local IsValid = IsValid
local LocalPlayer = LocalPlayer
local MsgC = MsgC
local CAMI = CAMI
local surface = surface
local team = team
-- luacheck: globals FACTION_SERVERADMIN
-- Roll information in chat.
ix.chat.Register("localevent", {
CanHear = (ix.config.Get("chatRange", 280) * 2),
OnChatAdd = function(self, speaker, text)
chat.AddText(Color(255, 150, 0), text)
end,
})
local broadcastIcon = ix.util.GetMaterial("willardnetworks/chat/broadcast_icon.png")
ix.chat.Register("localbroadcast", {
CanHear = (ix.config.Get("chatRange", 280) * 2),
CanSay = function(self, speaker, text)
if (speaker:Team() != FACTION_ADMIN and !speaker:GetCharacter():GetInventory():HasItem("wireless_microphone")) then
speaker:NotifyLocalized("notAllowed")
return false
end
end,
OnChatAdd = function(self, speaker, text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(broadcastIcon, Color(151, 161, 255), string.format("%s broadcasts locally \"%s\"", (speaker and speaker.Name and speaker:Name() or ""), text))
else
chat.AddText(Color(151, 161, 255), string.format("%s broadcasts locally \"%s\"", (speaker and speaker.Name and speaker:Name() or ""), text))
end
end
})
ix.chat.Register("localbroadcastme", {
CanHear = (ix.config.Get("chatRange", 280) * 2),
CanSay = function(self, speaker, text)
if (speaker:Team() != FACTION_ADMIN and !speaker:GetCharacter():GetInventory():HasItem("wireless_microphone")) then
speaker:NotifyLocalized("notAllowed")
return false
end
end,
OnChatAdd = function(self, speaker, text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(broadcastIcon, Color(151, 161, 255), string.format("*** %s %s", (speaker and speaker.Name and speaker:Name() or ""), text))
else
chat.AddText(Color(151, 161, 255), string.format("*** %s %s", (speaker and speaker.Name and speaker:Name() or ""), text))
end
end
})
ix.chat.Register("localbroadcastit", {
CanHear = (ix.config.Get("chatRange", 280) * 2),
CanSay = function(self, speaker, text)
if (speaker:Team() != FACTION_ADMIN and !speaker:GetCharacter():GetInventory():HasItem("wireless_microphone")) then
speaker:NotifyLocalized("notAllowed")
return false
end
end,
OnChatAdd = function(self, speaker, text)
if (ix.option.Get("standardIconsEnabled")) then
chat.AddText(broadcastIcon, Color(151, 161, 255), string.format("***' %s", text))
else
chat.AddText(Color(151, 161, 255), string.format("***' %s", text))
end
end
})
ix.chat.Register("announcement", {
OnChatAdd = function(self, speaker, text)
chat.AddText(Color(254, 238, 60), "[ADMIN] ", text)
end,
CanSay = function(self, speaker, text)
return true
end
})
-- STAFF CHAT
do
local CLASS = {}
local icon = ix.util.GetMaterial("icon16/medal_gold_3.png")
if (CLIENT) then
function CLASS:OnChatAdd(speaker, text, anonymous, data)
if (!IsValid(speaker)) then return end
if (speaker != LocalPlayer() and !ix.option.Get("staffChat")) then
local character = LocalPlayer():GetCharacter()
if (character and character:GetFaction() != FACTION_SERVERADMIN) then
MsgC(Color(255,215,0), "[Staff] ",
Color(128, 0, 255, 255), speaker:Name(), " (", speaker:SteamName(), "): ",
Color(255, 255, 255), text.."\n")
return
end
end
chat.AddText(icon, Color(255,215,0), "[Staff] ",
Color(128, 0, 255, 255), speaker:Name(), " (", speaker:SteamName(), "): ",
Color(255, 255, 255), text)
end
else
function CLASS:CanHear(speaker, listener)
return CAMI.PlayerHasAccess(listener, "Helix - Hear Staff Chat")
end
end
ix.chat.Register("staff_chat", CLASS)
end
-- GM CHAT
do
local CLASS = {}
local icon = ix.util.GetMaterial("icon16/rosette.png")
if (CLIENT) then
function CLASS:OnChatAdd(speaker, text, anonymous, data)
if (!IsValid(speaker)) then return end
chat.AddText(icon, Color(142, 28, 255), "[GM] ", Color(255, 215, 0, 255), speaker:Name(), " (", speaker:SteamName(), "): ", Color(255, 255, 255), text)
end
else
function CLASS:CanHear(speaker, listener)
return CAMI.PlayerHasAccess(listener, "Helix - Hear GM Chat")
end
end
ix.chat.Register("gm_chat", CLASS)
end
-- MENTOR CHAT
do
local CLASS = {}
local icon = ix.util.GetMaterial("icon16/user_suit.png")
if (CLIENT) then
function CLASS:OnChatAdd(speaker, text, anonymous, data)
if (!IsValid(speaker)) then return end
chat.AddText(icon, Color(66, 135, 245), "[Mentor] ", Color(66, 245, 191, 255), speaker:Name(), " (", speaker:SteamName(), "): ", Color(255, 255, 255), text)
end
else
function CLASS:CanHear(speaker, listener)
return CAMI.PlayerHasAccess(listener, "Helix - Hear Mentor Chat")
end
end
ix.chat.Register("mentor_chat", CLASS)
end
-- ACHIEVEMENT
do
local CLASS = {}
if (CLIENT) then
function CLASS:OnChatAdd(speaker, text, anonymous, data)
if (!IsValid(data[1])) then return end
if (data[2]) then
surface.PlaySound(data[2])
end
local target = data[1]
chat.AddText(team.GetColor(target:Team()), target:SteamName(), Color(255, 255, 255), " a gagné le succès : ",
Color( 255, 201, 0, 255 ), text)
end
end
ix.chat.Register("achievement_get", CLASS)
end

View File

@@ -0,0 +1,643 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local bit = bit
local IsValid = IsValid
local pairs = pairs
local table = table
local L = L
local netstream = netstream
local Entity = Entity
local print = print
local math = math
local tostring = tostring
local CAMI = CAMI
local Vector = Vector
local game = game
local RunConsoleCommand = RunConsoleCommand
local net = net
local player = player
local ipairs = ipairs
local ents = ents
local string = string
local timer = timer
local ix = ix
local PLUGIN = PLUGIN
--Links
ix.command.Add("Discord", {
description = "Obtenir un lien vers le serveur Discord",
privilege = "Basic Commands",
OnRun = function(self, client)
net.Start("ixOpenURL")
net.WriteString(ix.config.Get("DiscordLink"))
net.Send(client)
end,
bNoIndicator = true
})
ix.command.Add("Content", {
description = "Obtenir un lien vers le Workshop",
privilege = "Basic Commands",
OnRun = function(self, client)
net.Start("ixOpenURL")
net.WriteString(ix.config.Get("ContentLink"))
net.Send(client)
end
})
ix.command.Add("Forum", {
description = "Obtenir un lien vers les forums",
privilege = "Basic Commands",
OnRun = function(self, client)
net.Start("ixOpenURL")
net.WriteString(ix.config.Get("ForumLink"))
net.Send(client)
end,
bNoIndicator = true
})
--Basic Admin
ix.command.Add("PGI", {
description = "Obtenez les informations de base de quelqu'un et copiez son SteamID.",
arguments = {
bit.bor(ix.type.player, ix.type.optional)
},
--alias = "PlyGetInfo",
privilege = "Commandes d'administration de base",
OnRun = function(self, client, target)
if (!target) then
target = client:GetEyeTraceNoCursor().Entity
end
if (!IsValid(target) or !target:IsPlayer()) then
client:NotifyLocalized("bastionPGIInvalidTarget")
return
end
net.Start("ixPlayerInfo")
net.WriteEntity(target)
net.Send(client)
end,
bNoIndicator = true
})
ix.command.Add("PrintStaffList", {
alias = "PSL",
description = "Imprimez une liste des membres du personnel en ligne.",
OnRun = function(self, client)
local staff = {}
local bFound = false
for _, v in ipairs(player.GetAll()) do
local incognitoSetting = ix.option.Get(v, "iconIncognitoMode", false)
local iconIncognitoMode = !client:IsAdmin() and !client:IsSuperAdmin() and incognitoSetting
if (v:IsAdmin() or v:IsSuperAdmin()) and !iconIncognitoMode then
local userGroup = v:GetUserGroup()
staff[userGroup] = staff[userGroup] or {}
staff[userGroup][#staff[userGroup] + 1] = v
bFound = true
end
end
local toSend = {}
for k, v in pairs(staff) do
toSend[#toSend + 1] = {name = k, players = v}
end
table.SortByMember(toSend, "name", true)
if (bFound) then
net.Start("ixStaffList")
net.WriteUInt(#toSend, 8)
for _, v in ipairs(toSend) do
net.WriteString(v.name)
net.WriteUInt(#v.players, 8)
for i = 1, #v.players do
net.WriteEntity(v.players[i])
end
end
net.Send(client)
else
client:Notify("Il n'y a pas de STAFF en ligne actuellement.")
end
end,
bNoIndicator = true
})
ix.command.Add("PrintFactionList", {
alias = "PFL",
description = "Imprimer une liste des membres d'une faction actuellement en ligne (y compris sur un autre personnage).",
arguments = {
ix.type.string
},
privilege = "Basic Admin Commands",
OnRun = function(self, client, name)
if (name == "") then
return "@invalidArg", 2
end
local faction = ix.faction.teams[name]
if (!faction) then
for _, v in ipairs(ix.faction.indices) do
if (ix.util.StringMatches(L(v.name, client), name) or ix.util.StringMatches(v.uniqueID, name)) then
faction = v
break
end
end
end
if (faction) then
local players = {}
for _, v in ipairs(player.GetAll()) do
if (v:HasWhitelist(faction.index)) then
players[#players + 1] = v
end
end
net.Start("ixStaffList")
net.WriteUInt(1, 8)
net.WriteString(faction.name)
net.WriteUInt(#players, 8)
for i = 1, #players do
net.WriteEntity(players[i])
end
net.Send(client)
else
return "@invalidFaction"
end
end,
bNoIndicator = true
})
ix.command.Add("PlaySound", {
description = "Jouez un son pour tous les joueurs (lorsqu'aucune portée n'est donnée) ou ceux qui sont proches de vous.",
arguments = {
ix.type.string,
bit.bor(ix.type.number, ix.type.optional)
},
privilege = "Basic Admin Commands",
OnRun = function(self, client, sound, range)
local targets = range and {} or player.GetAll()
if (range) then
range = range * range
local clientPos = client:EyePos()
for _, target in ipairs(player.GetAll()) do
if (target:EyePos():DistToSqr(clientPos) < range) then
targets[#targets + 1] = target
end
end
end
net.Start("ixPlaySound")
net.WriteString(PLUGIN.soundAlias[sound] or sound)
net.Send(targets)
end,
indicator = "chatPerforming"
})
ix.command.Add("ScreenShake", {
description = "Shakes the screen of everyone in the specified range. Specify the amplitude, the frequency and the radius for it to work.",
arguments = {
ix.type.number,
ix.type.number,
ix.type.number,
ix.type.number
},
argumentNames = {"time(seconds)", "amplitude", "frequency", "radius"},
privilege = "Basic Admin Commands",
OnRun = function(self, client, seconds, strength, frequency, radius)
local vector = client:GetPos()
util.ScreenShake(vector, strength or 5, frequency or 5, seconds, radius)
end,
indicator = "chatPerforming"
})
ix.command.Add("PlaySoundGlobal", {
description = "Jouez un son pour tous les joueurs.",
arguments = {
ix.type.string,
},
privilege = "Basic Admin Commands",
OnRun = function(self, client, sound)
net.Start("ixPlaySound")
net.WriteString(PLUGIN.soundAlias[sound] or sound)
net.WriteBool(true)
net.Send(player.GetAll())
end,
indicator = "chatPerforming"
})
ix.command.Add("ShowEdicts", {
description = "Renvoie le nombre d'entités en réseau actuellement sur le serveur.",
privilege = "Basic Admin Commands",
OnRun = function(self, client)
local edictsCount = ents.GetEdictCount()
local edictsLeft = 8192 - edictsCount
return string.format("Il y a actuellement %s édits sur le serveur. Vous pouvez avoir jusqu'à %s de plus.", edictsCount, edictsLeft)
end,
bNoIndicator = true
})
ix.command.Add("ShowEntsInRadius", {
description = "Affiche une liste d'entités dans un rayon donné.",
privilege = "Basic Admin Commands",
arguments = {ix.type.number},
OnRun = function(self, client, radius)
local entities = {}
local pos = client:GetPos()
for _, v in pairs(ents.FindInSphere(pos, radius)) do
if (!IsValid(v)) then continue end
entities[#entities + 1] = table.concat({v:EntIndex(), v:GetClass(), v:GetModel() or "no model", v:GetPos():Distance(pos), v:MapCreationID()}, ", ")
end
netstream.Start(client, "ixShowEntsInRadius", table.concat(entities,"\n"))
client:NotifyLocalized("entsPrintedInConsole")
end,
bNoIndicator = true,
})
ix.command.Add("RemoveEntityByID", {
description = "Affiche une liste d'entités dans un rayon donné.",
superAdminOnly = true,
arguments = {ix.type.number},
OnRun = function(self, client, number)
local entity = Entity(number)
if (IsValid(entity)) then
client:NotifyLocalized("entityRemoved", number, entity:GetClass())
entity:Remove()
else
client:NotifyLocalized("entityNotFound", number)
end
end,
bNoIndicator = true,
})
if (CLIENT) then
netstream.Hook("ixShowEntsInRadius", function(text)
print(text)
end)
end
ix.command.Add("LocalEvent", {
description = "@cmdLocalEvent",
privilege = "Event",
arguments = {
ix.type.string,
bit.bor(ix.type.number, ix.type.optional)
},
OnRun = function(self, client, event, range)
local _range = range or (ix.config.Get("chatRange", 280) * 2)
ix.chat.classes.localevent.range = _range * _range
local doubleCommand = false
-- This could probably be done a bit smarter but I'm sure it'll do.
if (string.Left(string.lower(event), 11) == "/localevent") then
doubleCommand = true
event = string.Right(event, #event - 12)
elseif (string.Left(string.lower(event), 10) == "localevent") then
doubleCommand = true
event = string.Right(event, #event - 11)
end
if (doubleCommand) then
client:NotifyLocalized("textDoubleCommand", "/LocalEvent")
end
ix.chat.Send(client, "localevent", event)
end,
indicator = "chatPerforming"
})
ix.command.Add("RemovePersistedProps", {
description = "@cmdRemovePersistedProps",
superAdminOnly = true,
arguments = {
ix.type.number
},
OnRun = function(self, client, radius)
if (radius < 0) then
client:Notify("Radius must be a positive number!")
return
end
for _, entity in ipairs(ents.FindInSphere(client:GetPos(), radius)) do
if (!entity:GetNetVar("Persistent")) then continue end
entity:Remove()
end
client:Notify("Removed all persisted props in a radius of " .. radius .. " units.")
end
})
ix.command.Add("Announce", {
description = "@cmdAnnounce",
arguments = {
ix.type.text
},
OnRun = function(self, client, event)
ix.chat.Send(client, "announcement", event)
end,
OnCheckAccess = function(self, client)
return !client or CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands")
end,
indicator = "chatTyping"
})
-- Help
ix.command.Add("Help", {
description = "@cmdStaffHelp",
arguments = ix.type.text,
alias = {"GMHelp", "ModHelp"},
OnRun = function(self, client, text)
client:Say("@ " .. text)
end,
OnCheckAccess = function(self, client)
return !CAMI.PlayerHasAccess(client, "Helix - Hear Staff Chat")
end,
indicator = "chatTyping"
})
-- Admin Chat
ix.command.Add("Staff", {
description = "Discutez avec d'autres membres du STAFF.",
arguments = ix.type.text,
privilege = "Hear Staff Chat",
alias = {"Op", "Mod", "ModChat"},
OnRun = function(self, client, text)
ix.chat.Send(client, "staff_chat", text)
end,
indicator = "chatTyping"
})
-- Gamemaster Chat
ix.command.Add("GameMaster", {
description = "Discutez avec d'autres Gamemasters.",
arguments = ix.type.text,
privilege = "Hear GM Chat",
alias = {"GMChat", "GM"},
OnRun = function(self, client, text)
ix.chat.Send(client, "gm_chat", text)
end,
indicator = "chatTyping"
})
-- Mentor Chat
ix.command.Add("Mentor", {
description = "Discutez avec d'autres mentors.",
arguments = ix.type.text,
privilege = "Hear Mentor Chat",
alias = {"MChat", "M"},
OnRun = function(self, client, text)
ix.chat.Send(client, "mentor_chat", text)
end,
indicator = "chatTyping"
})
-- Fun Stuff
ix.command.Add("Achievement", {
description = "Quelqu'un a gagné une réalisation spéciale !",
arguments = {
ix.type.player,
ix.type.text
},
privilege = "Fun Stuff",
OnRun = function(self, client, target, text)
ix.chat.Send(client, "achievement_get", text, false, nil,
{target, "ambient/water/drip" .. math.random( 1, 4 ) .. ".wav"})
end,
indicator = "chatTyping"
})
ix.command.Add("DarwinAward", {
description = "Quelqu'un a mérité un exploit : il a fait le sacrifice ultime pour augmenter le QI moyen de l'humanité.",
arguments = {
ix.type.player
},
privilege = "Fun Stuff",
OnRun = function(self, client, target)
if (!target:Alive()) then
local pos = target:GetPos()
target:Spawn()
target:SetPos(pos)
end
target:SetMoveType(MOVETYPE_WALK)
target:SetVelocity(Vector(0, 0, 4000))
timer.Simple(1, function() PLUGIN:Explode(target) end)
ix.chat.Send(client, "achievement_get", "DARWIN AWARD", false, nil,
{target, "ambient/alarms/razortrain_horn1.wav"})
end,
indicator = "chatTyping"
})
ix.command.Add("PlyRocket", {
description = "To infinity, and beyond!.",
arguments = {
ix.type.player
},
privilege = "Fun Stuff",
OnRun = function(self, client, target)
if (!target:Alive()) then
local pos = target:GetPos()
target:Spawn()
target:SetPos(pos)
end
target:SetMoveType(MOVETYPE_WALK)
target:SetVelocity(Vector(0, 0, 4000))
timer.Simple(1, function() PLUGIN:Explode(target) end)
end,
bNoIndicator = true
})
ix.command.Add("SetTimeScale", {
description = "@cmdTimeScale",
arguments = {
bit.bor(ix.type.number, ix.type.optional)
},
privilege = "Fun Stuff",
OnRun = function(self, client, number)
local scale = math.Clamp(number or 1, 0.001, 5)
game.SetTimeScale(scale)
for _, v in ipairs(player.GetAll()) do
if (self:OnCheckAccess(v)) then
v:NotifyLocalized("bastionTimeScale", client:Name(), scale)
end
end
end,
bNoIndicator = true
})
ix.command.Add("SetGravity", {
description = "@cmdGravity",
arguments = {
bit.bor(ix.type.number, ix.type.optional)
},
privilege = "Fun Stuff",
OnRun = function(self, client, number)
RunConsoleCommand("sv_gravity", number)
for _, v in ipairs(player.GetAll()) do
if (self:OnCheckAccess(v)) then
v:NotifyLocalized("bastionGravity", client:Name(), number)
end
end
end,
bNoIndicator = true
})
-- lookup commands
ix.command.Add("LookupSteamID", {
description = "Lookup a SteamID in the Bastion user database",
arguments = {
ix.type.text
},
privilege = "Bastion Lookup",
OnRun = function(self, client, target)
if (string.find(target, "^STEAM_%d+:%d+:%d+$")) then
PLUGIN:LookupSteamID(client, target)
return
elseif (string.len(target) == 17 and string.find(target, "^%d+$")) then
PLUGIN:LookupSteamID(client, target)
return
end
target = ix.util.FindPlayer(target, false)
client:NotifyLocalized("bastionTargetSelected", target:Name())
PLUGIN:LookupSteamID(client, target:SteamID64())
end,
bNoIndicator = true
})
ix.command.Add("LookupIPUsers", {
description = "Lookup a SteamID in the Bastion IP database",
arguments = {
ix.type.text
},
privilege = "Bastion Lookup",
OnRun = function(self, client, target)
if (string.find(target, "^STEAM_%d+:%d+:%d+$")) then
PLUGIN:LookupIPUsers(client, target)
return
elseif (string.len(target) == 17 and string.find(target, "^%d+$")) then
PLUGIN:LookupIPUsers(client, target)
return
end
target = ix.util.FindPlayer(target, false)
client:NotifyLocalized("bastionTargetSelected", target:Name())
PLUGIN:LookupIPUsers(client, target:SteamID64())
end,
bNoIndicator = true
})
ix.command.Add("ProxyWhitelist", {
description = "Whitelist a player as trusted to disable future proxy checks.",
arguments = {
ix.type.player
},
privilege = "Bastion Whitelist",
OnRun = function(self, client, target)
if (PLUGIN:WhitelistPlayer(target)) then
client:NotifyLocalized("whitelistDone")
else
client:NotifyLocalized("whitelistError")
end
end,
indicator = "chatTyping"
})
ix.command.Add("PlyGetCharacters", {
description = "Get a list of a player's characters.",
arguments = {
ix.type.player
},
adminOnly = true,
OnRun = function(self, client, target)
client:ChatNotify(target:SteamName() .. "'s characters:")
client:ChatNotify("====================")
for _, character in pairs(target.ixCharList) do
client:ChatNotify(ix.char.loaded[character].vars.name)
end
end
})
ix.command.Add("LTARP", {
description = "Automatically ban a player for leaving to avoid RP after a grace period.",
arguments = {
ix.type.string,
ix.type.number,
bit.bor(ix.type.text, ix.type.optional),
},
adminOnly = true,
OnRun = function(self, client, steamID, days, reason)
local target = player.GetBySteamID64(steamID) or player.GetBySteamID(steamID)
if (target) then
client:Notify(target:SteamName().." is still on the server as '"..target:Name().."!")
return
end
if (days > 100) then
client:Notify("Invalid duration entered. Max ban length is 100 days.")
return
end
if (string.find(string.upper(steamID), "^STEAM")) then
steamID = util.SteamIDTo64(string.upper(steamID))
end
if (!PLUGIN.disconnects[steamID]) then
client:Notify("Could not find a disconnect for "..steamID..", manually ban them if needed.")
return
end
local info = PLUGIN.disconnects[steamID]
if (info.timer) then
client:Notify(steamID.." is already tagged for LTARP by "..info.bannedByName..".")
return
end
local reconnectTime, maxBanDelay = 30, 40
if (info.time + reconnectTime * 60 < os.time()) then
if (info.time + maxBanDelay * 60 < os.time()) then
client:Notify(steamID.." disconnected more than "..maxBanDelay.." minutes ago already. Manually ban them if needed.")
return
end
RunConsoleCommand("sam", "banid", steamID, tostring(days * 60 * 24), reason != "" and reason or "Leaving to avoid RP. Appeal on willard.network ~"..client:SteamName())
return
end
local uniqueID = "ixLTARP"..steamID
local bannedBy = client and client:SteamName() or "console"
timer.Create(uniqueID, info.time - os.time() + reconnectTime * 60, 1, function()
if (IsValid(client)) then
client:Notify(steamID.." did not reconnect and has been banned.")
end
RunConsoleCommand("sam", "banid", steamID, tostring(days * 60 * 24), reason != "" and reason or "Leaving to avoid RP. Appeal on willard.network ~"..bannedBy)
end)
info.timer = uniqueID
info.bannedBy = client
info.bannedByName = client and client:SteamName() or "console"
client:Notify("Timer set! "..steamID.." will be banned in "..math.ceil((info.time - os.time() + reconnectTime * 60) / 60).." minutes.")
end
})

View File

@@ -0,0 +1,324 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local properties = properties
local IsValid = IsValid
local RunConsoleCommand = RunConsoleCommand
local tostring = tostring
local Derma_StringRequest = Derma_StringRequest
local CAMI = CAMI
local hook = hook
local SetClipboardText = SetClipboardText
local LocalPlayer = LocalPlayer
local net = net
local ix = ix
local PLUGIN = PLUGIN
properties.Add("ixCopyCharName", {
MenuLabel = "#Copy Character Name",
Order = 0,
MenuIcon = "icon16/user.png",
Filter = function(self, target)
return target:IsPlayer()
and CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands")
and hook.Run("CanProperty", LocalPlayer(), "ixCopyCharName", target) != false
end,
Action = function(self, target)
SetClipboardText(target:Name())
LocalPlayer():NotifyLocalized("bastionCopiedCharName")
end,
})
properties.Add("ixCopySteamName", {
MenuLabel = "#Copy Steam Name",
Order = 1,
MenuIcon = "icon16/user.png",
Filter = function(self, target)
return target:IsPlayer()
and CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands")
and hook.Run("CanProperty", LocalPlayer(), "ixCopySteamName", target) != false
end,
Action = function(self, target)
SetClipboardText(target:SteamName())
LocalPlayer():NotifyLocalized("bastionCopiedSteamName")
end,
})
properties.Add("ixCopySteamID", {
MenuLabel = "#Copy Steam ID",
Order = 2,
MenuIcon = "icon16/user.png",
Filter = function(self, target)
return target:IsPlayer()
and CAMI.PlayerHasAccess(LocalPlayer(), "Helix - Basic Admin Commands")
and hook.Run("CanProperty", LocalPlayer(), "ixCopySteamID", target) != false
end,
Action = function(self, target)
SetClipboardText(target:SteamID())
LocalPlayer():NotifyLocalized("bastionCopiedSteamID")
end,
})
properties.Add("ixViewInventory", {
MenuLabel = "#View Inventory",
Order = 10,
MenuIcon = "icon16/eye.png",
PrependSpacer = true,
Filter = function(self, target, client)
client = client or LocalPlayer()
return target:IsPlayer()
and CAMI.PlayerHasAccess(client, "Helix - View Inventory")
and hook.Run("CanProperty", client, "ixViewInventory", target) != false
end,
Action = function(self, target)
self:MsgStart()
net.WriteEntity(target)
self:MsgEnd()
end,
Receive = function(self, length, client)
local target = net.ReadEntity()
if (!IsValid(target)) then return end
if (!self:Filter(target, client)) then return end
PLUGIN:OpenInventory(client, target)
end
})
properties.Add("ixSetHealth", {
MenuLabel = "#Health",
Order = 100,
PrependSpacer = true,
MenuIcon = "icon16/heart.png",
Filter = function(self, target, client)
client = client or LocalPlayer()
return target:IsPlayer()
and (sam and (client:HasPermission("hp") or client:HasPermission("slay"))
or CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands"))
and hook.Run("CanProperty", client, "ixSetHealth", target) != false
end,
MenuOpen = function(self, option, target)
local submenu = option:AddSubMenu()
local maxHealth = target:GetMaxHealth()
local step = maxHealth > 100 and -50 or -25
if (sam) then
if (LocalPlayer():HasPermission("hp")) then
for i = maxHealth, 1, step do
submenu:AddOption(i, function() RunConsoleCommand("sam", "hp", target:SteamID(), tostring(i)) end)
end
submenu:AddOption("1", function() RunConsoleCommand("sam", "hp", target:SteamID(), "1") end)
end
if (LocalPlayer():HasPermission("slay")) then
submenu:AddOption("Kill", function() RunConsoleCommand("sam", "slay", target:SteamID()) end)
end
else
for i = maxHealth, 1, step do
submenu:AddOption(i, function() self:SetHealth(target, i) end)
end
submenu:AddOption("1", function() self:SetHealth(target, 1) end)
submenu:AddOption("Kill", function() self:SetHealth(target, 0) end)
end
end,
SetHealth = function(self, target, health)
self:MsgStart()
net.WriteEntity(target)
net.WriteUInt(health, 16)
self:MsgEnd()
end,
Receive = function(self, length, client)
local target = net.ReadEntity()
local health = net.ReadUInt(16)
if (!IsValid(target)) then return end
if (!self:Filter(target, client)) then return end
if (health > 0) then
target:SetHealth(health)
ix.log.Add(client, "bastionSetHealth", target)
else
target:Kill()
ix.log.Add(client, "bastionSlay", target)
end
end
})
properties.Add("ixSetArmor", {
MenuLabel = "#Armor",
Order = 110,
MenuIcon = "icon16/heart.png",
Filter = function(self, target, client)
client = client or LocalPlayer()
return target:IsPlayer()
and (sam and client:HasPermission("armor")
or CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands"))
and hook.Run("CanProperty", client, "ixSetArmor", target) != false
end,
MenuOpen = function(self, option, target)
local submenu = option:AddSubMenu()
local maxArmor = 100
local step = maxArmor > 100 and -50 or -10
if (sam) then
for i = maxArmor, 1, step do
submenu:AddOption(i, function() RunConsoleCommand("sam", "armor", target:SteamID(), tostring(i)) end)
end
submenu:AddOption("Remove", function() RunConsoleCommand("sam", "armor", target:SteamID(), "0") end)
else
for i = maxArmor, 1, step do
submenu:AddOption(i, function() self:SetArmor(target, i) end)
end
submenu:AddOption("Remove", function() self:SetArmor(target, 0) end)
end
end,
SetArmor = function(self, target, armor)
self:MsgStart()
net.WriteEntity(target)
net.WriteUInt(armor, 16)
self:MsgEnd()
end,
Receive = function(self, length, client)
local target = net.ReadEntity()
local armor = net.ReadUInt(16)
if (!IsValid(target)) then return end
if (!self:Filter(target, client)) then return end
target:SetArmor(armor)
ix.log.Add(client, "bastionSetArmor", target)
end
})
properties.Add("ixSetCharName", {
MenuLabel = "#Set Name",
Order = 120,
MenuIcon = "icon16/book_edit.png",
PrependSpacer = true,
Filter = function(self, entity, client)
return CAMI.PlayerHasAccess(client, "Helix - CharSetName", nil) and entity:IsPlayer() and entity:GetCharacter()
end,
Action = function(self, entity)
Derma_StringRequest("Set Name", "Set the character's name", entity:Name(), function(text)
if (text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
if (CAMI.PlayerHasAccess(client, "Helix - CharSetName", nil)) then
local entity = net.ReadEntity()
local text = net.ReadString()
if (IsValid(entity) and entity:IsPlayer() and entity:GetCharacter()) then
local oldName = entity:GetCharacter():GetName()
entity:GetCharacter():SetName(text)
ix.log.Add(client, "bastionSetName", entity:GetCharacter(), oldName)
end
end
end
})
properties.Add("ixSetCharDescription", {
MenuLabel = "#Set Description",
Order = 121,
MenuIcon = "icon16/book_edit.png",
Filter = function(self, entity, client)
return CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil) and entity:IsPlayer() and entity:GetCharacter()
end,
Action = function(self, entity)
Derma_StringRequest("Set Description", "Set the character's description", entity:GetCharacter():GetDescription(), function(text)
if (text == "") then return end
self:MsgStart()
net.WriteEntity(entity)
net.WriteString(text)
self:MsgEnd()
end)
end,
Receive = function(self, length, client)
if (CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then
local entity = net.ReadEntity()
local text = net.ReadString()
if (IsValid(entity) and entity:IsPlayer() and entity:GetCharacter()) then
entity:GetCharacter():SetDescription(text)
ix.log.Add(client, "bastionSetDesc", entity:GetCharacter())
end
end
end
})
properties.Add("ixPropViewOwner", {
MenuLabel = "Voir propriétaire",
Order = 405,
MenuIcon = "icon16/magnifier.png",
Filter = function(self, entity, client)
if (entity:GetClass() == "prop_physics" and CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then return true end
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
local ownerCharacter = entity.ownerCharacter
local ownerName = entity.ownerName
local ownerSteamID = entity.ownerSteamID
if (ownerCharacter and ownerName and ownerSteamID) then
client:ChatNotifyLocalized("bastionPropOwnerInformation", ownerCharacter, ownerName, ownerSteamID)
else
client:ChatNotifyLocalized("bastionPropOwnerUnknown")
end
end
})

View File

@@ -0,0 +1,54 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Remake the connect & disconnect chat classes to stop the default ones.
function PLUGIN:InitializedChatClasses()
ix.chat.classes["connect"] = nil
ix.chat.classes["disconnect"] = nil
ix.chat.Register("new_connect", {
CanSay = function(_, speaker, text)
return !IsValid(speaker)
end,
OnChatAdd = function(_, speaker, text)
local icon = ix.util.GetMaterial("willardnetworks/chat/connected_icon.png")
chat.AddText(icon, Color(151, 153, 152), L("playerConnected", text))
end,
noSpaceAfter = true
})
ix.chat.Register("new_disconnect", {
CanSay = function(_, speaker, text)
return !IsValid(speaker)
end,
OnChatAdd = function(_, speaker, text)
local icon = ix.util.GetMaterial("willardnetworks/chat/disconnected_icon.png")
chat.AddText(icon, Color(151, 153, 152), L("playerDisconnected", text))
end,
noSpaceAfter = true
})
ix.chat.Register("bastionPlayerDeath", {
CanSay = function(_, speaker, text)
return true
end,
OnChatAdd = function(_, speaker, text)
local icon = ix.util.GetMaterial("icon16/user_red.png")
chat.AddText(icon, Color(255, 0, 0), text)
end,
CanHear = function(_, speaker, listener)
return listener:IsAdmin() and ix.option.Get(listener, "playerDeathNotification")
end
})
end

View File

@@ -0,0 +1,289 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local IsValid = IsValid
local ix = ix
PLUGIN.name = "Bastion"
PLUGIN.author = "Gr4Ss"
PLUGIN.description = "Some admin extensions for Helix."
local CAMI = CAMI
CAMI.RegisterPrivilege({
Name = "Helix - Hear Staff Chat",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Hear GM Chat",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Hear Mentor Chat",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Fun Stuff",
MinAccess = "superadmin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Basic Commands",
MinAccess = "user"
})
CAMI.RegisterPrivilege({
Name = "Helix - Basic Admin Commands",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Full Remover Tool",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - HL2 Tools",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Bastion Whitelist",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - View Inventory",
MinAccess = "superadmin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Increase Character Limit",
MinAccess = "admin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Bastion Lookup",
MinAccess = "superadmin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Container Password",
MinAccess = "superadmin"
})
CAMI.RegisterPrivilege({
Name = "Helix - Proxy Notify",
MinAccess = "superadmin"
})
ix.option.Add("pgi", ix.type.bool, true, {category = "Administration"})
ix.option.Add("playerDeathNotification", ix.type.bool, true, {category = "Administration", bNetworked = true})
ix.config.Add("netLoggingEnabled", false, "Enable or disable net logging into the database (WARNING: PERFORMANCE IMPACT)", nil, {
category = "Bastion"
})
ix.config.Add("netAntiSpam", true, "Enable or disable net anti-spam (WARNING: PERFORMANCE IMPACT)", nil, {
category = "Bastion"
})
ix.config.Add("suppressOnPlayerChat", true, "Suppress the default OnPlayerChat hook (should not be used by helix)", nil, {
category = "Bastion"
})
ix.config.Add("maxCharactersIncreased", 5, "The maximum number of characters a player can have if they have the increased character limit permission.", nil, {
data = {min = 1, max = 50},
category = "Personnages"
})
ix.config.Add("charCreateInterval", 5, "How many minutes there should be between 2 successful character creations of one player (to avoid character spam).", nil, {
data = {min = 1, max = 50},
category = "Personnages"
})
ix.config.Add("AllowContainerSpawn", false, "Allow anyone to directly spawn containers by spawning in their prop. Disallowing this will require admins to create containers from a prop using the context menu.", nil, {
category = "Conteneurs"
})
ix.config.Add("VPNKick", false, "Kick new users if they use a VPN.", nil, {
category = "Bastion"
})
ix.config.Add("ProxyAlwaysAlert", true, "Always Discord Alert for new joiners with a VPN.", nil, {
category = "Bastion"
})
ix.config.Add("showConnectMessages", true, "Whether or not to show notifications when players connect to the server. When off, only Staff will be notified.", nil, {
category = "Serveur"
})
ix.config.Add("showDisconnectMessages", true, "Whether or not to show notifications when players disconnect from the server. When off, only Staff will be notified.", nil, {
category = "Serveur"
})
ix.config.Add("DiscordLink", "https://discord.gg/HbDjUQd", "Invite link to the discord.", nil, {
category = "Bastion"
})
ix.config.Add("ContentLink", "https://steamcommunity.com/sharedfiles/filedetails/?id=2934933494", "Link to the workshop collection.", nil, {
category = "Bastion"
})
ix.config.Add("ForumLink", "https://willard.network", "Link to the forums", nil, {
category = "Bastion"
})
ix.config.Add("EdictWarningLimit", 1024, "How many edicts can be left before warning messages start to appear.", nil, {
data = {min = 100, max = 1024},
category = "Bastion"
})
ix.flag.Add("a", "Accès au duplicateur.")
ix.lang.AddTable("english", {
getPlayerInfo = "Get Player Info",
optStaffChat = "Show Staff Chat on all characters",
optdStaffChat = "Turns on/off staff chat on all characters. When off, will only show staff chat while in observer or on an admin character.",
optPgi = "Copy Steam ID to clipboard on 'PGI'/'View Player'",
optdPgi = "Allows you to turn on/off the automatic copy-to-clipboard of a player's SteamID when using the PGI command or 'View Player' context menu option.",
cmdStaffHelp = "Call for help from all the staff.\n",
cmdAnnounce = "Make an OOC admin announcement to the entire server.",
cmdLocalEvent = "Make an IC admin event that can only be heard within a given radius.",
bastionPGIInvalidTarget = "You must enter or be looking at a valid target.",
bastionTakingItemsTooQuickly = "You are taking items too quickly! Please slow down.",
bastionItemDropSpamKick = "%s was kicked for item drop exploiting.",
bastionItemDropSpamWarn = "%s was warned for item drop exploiting.",
bastionItemDropTooQuick = "You are dropping items too quickly! Please slow down.",
bastionItemTakeWarn = "%s was warned for taking items too quickly.",
bastionItemTakeKick = "%s was kicked for dropping items too quickly.",
charCreateTooFast = "You are creating characters too fast. Please wait at least %d minutes between attempts.",
bastionCopiedCharName = "Character name copied",
bastionCopiedSteamName = "Steam name copied",
bastionCopiedSteamID = "Steam ID copied",
bastionGoto = "Go to player",
bastionCopyCharName = "Copy character name",
bastionCopySteamName = "Copy steam name",
bastionNoRecordFound = "Could not find any records for %s.",
bastionResultsPrinted = "Results were printed in console.",
bastionProxyNotify = "%s connected as new player while using a VPN/Proxy.",
bastionPropOwnerInformation = "The owner of this prop is %s (%s - %s).",
bastionPropOwnerUnknown = "The owner of this prop has not been registered!",
whitelistDone = "Player was whitelisted.",
whitelistError = "Something went wrong whitelisting the player. Ask a dev.",
cmdTimeScale = "Change the timescale (min 0.001, max 5).",
bastionTimeScale = "%s has set the timescale to %d.",
cmdGravity = "Change the gravity.",
bastionGravity = "%s has set the gravity to %d.",
edictWarning = "Only %d edicts are left! Total edict count is currently: %d/8192!",
edictCritical = "Only %d edicts are left! Total edict count is currently: %d/8192! Emergency Cleanup Required!",
entsPrintedInConsole = "Entity list has been printed in console.",
entityRemoved = "Entity %d (%s) was removed!",
entityNotFound = "Entity %d was not found/is not valid.",
optPlayerDeathNotification = "Player Death Notification",
optdPlayerDeathNotification = "Whether to send a chat message when a player dies.",
cmdRemovePersistedProps = "Remove all persisted props in a radius around you."
})
ix.lang.AddTable("spanish", {
bastionCopySteamName = "Copiar nombre de Steam",
bastionPGIInvalidTarget = "Debes especificar o estar mirando a un objetivo válido.",
cmdLocalEvent = "Haz un evento IC de administrador que sólo pueda ser escuchado dentro de un radio determinado.",
bastionNoRecordFound = "No se ha podido encontrar ningún registro para %s.",
cmdAnnounce = "Haz un anuncio OOC de administrador a todo el servidor.",
cmdGravity = "Cambia la gravedad.",
bastionCopiedSteamID = "Steam ID copiada",
bastionProxyNotify = "%s se ha conectado como nuevo jugador mientras usa una VPN/Proxy.",
bastionTakingItemsTooQuickly = "¡Estás agarrando objetos demasiado rápido! Por favor, reduce la velocidad.",
optdStaffChat = "Activa/desactiva el Chat de Staff en todos los personajes. Cuando está desactivado, sólo se mostrará el Chat de Staff mientras se esté en observer o en un personaje administrativo.",
entityNotFound = "La entidad %d no fue encontrada/no es válida.",
whitelistDone = "El jugador estaba en la Whitelist.",
bastionCopiedCharName = "Nombre del personaje copiado",
getPlayerInfo = "Obtener información del jugador",
bastionCopyCharName = "Copiar el nombre del personaje",
charCreateTooFast = "Estás creando personajes demasiado rápido. Por favor, espera al menos %d minutos entre intentos.",
entsPrintedInConsole = "La lista de entidades se ha impreso en la consola.",
bastionItemDropTooQuick = "¡Estás soltando objetos demasiado rápido! Por favor, baja la velocidad.",
bastionGravity = "%s ha fijado la gravedad en %d.",
entityRemoved = "¡La entidad %d (%s) ha sido eliminada!",
cmdStaffHelp = "Pide ayuda a todo el Staff.\n",
bastionCopiedSteamName = "Nombre de Steam copiado",
bastionItemTakeWarn = "%s fue advertido por agarrar objetos demasiado rápido.",
bastionResultsPrinted = "Los resultados se imprimieron en la consola.",
optStaffChat = "Mostrar el Chat de Staff en todos los personajes",
bastionGoto = "Ir al jugador",
cmdTimeScale = "Cambie la escala de tiempo (mínimo 0,001, máximo 5).",
whitelistError = "Algo fue mal cuando se intentó meter al jugador en la whitelist. Contacta con un desarrollador.",
bastionTimeScale = "%s ha fijado la escala de tiempo en %d.",
bastionItemDropSpamKick = "%s ha sido expulsado por exploits relacionados con item-dropping.",
optdPgi = "Te permite activar/desactivar la copia automática al portapapeles del SteamID de un jugador cuando usa el comando PGI o la opción del menú contextual 'Ver Jugador'.",
bastionItemDropSpamWarn = "%s ha sido advertido del uso de exploits relacionados con item-dropping.",
bastionItemTakeKick = "%s ha sido expulsado por soltar objetos demasiado rápido.",
optPgi = "Copiar Steam ID al portapapeles en el 'PGI'/'Ver Jugador'",
edictWarning = "¡Solamente quedan disponibles %d edictos! ¡El conteo total de edictos es de: %d/8192!"
})
PLUGIN.soundAlias = {
["restricted_block_deploy"] = "voices/dispatch/restrictedblock_deployment.wav",
["restricted_block"] = "voices/dispatch/restrictedblock_warning.wav",
["access_restricted"] = "voices/dispatch/access_restricted.wav",
["anticivil_evading"] = "voices/dispatch/anticivil_evading.wav",
["civil_insurrection"] = "voices/dispatch/civil_insurrection.wav",
["victory_music"] = "music/scary_tense/victory_music.mp3",
}
ix.util.Include("cl_plugin.lua")
ix.util.Include("sh_classes.lua")
ix.util.Include("sh_commands.lua")
ix.util.Include("sh_context.lua")
ix.util.Include("sh_hooks.lua")
ix.util.Include("sv_hooks.lua")
ix.util.Include("sv_plugin.lua")
ix.util.Include("modules/sh_bindchecker.lua")
function PLUGIN:GetMaxPlayerCharacter(client)
if (CAMI.PlayerHasAccess(client, "Helix - Increase Character Limit")) then
return ix.config.Get("maxCharactersIncreased", 8)
end
end
function PLUGIN:CanProperty(client, property, entity)
if (property == "container_setpassword" and !CAMI.PlayerHasAccess(client, "Helix - Container Password")) then
return false
end
end
function PLUGIN:CanPlayerSpawnContainer()
if (!ix.config.Get("AllowContainerSpawn")) then
return false
end
end
function PLUGIN:CanPlayerAccessDoor(client)
if (client:GetMoveType() == MOVETYPE_NOCLIP and !client:InVehicle()) then return true end
if (ix.faction.Get(client:Team()).lockAllDoors) then return true end
end
PLUGIN.removeWhitelist = {
["prop_physics"] = true,
["prop_ragdoll"] = true
}
local hl2Tools = {
["env_headcrabcanister"] = true,
["item_ammo_crate"] = true,
["item_item_crate"] = true,
["prop_door"] = true,
["prop_thumper"] = true
}
function PLUGIN:CanTool(client, trace, tool)
if (tool == "remover" and !CAMI.PlayerHasAccess(client, "Helix - Full Remover Tool")) then
if (IsValid(trace.Entity) and !self.removeWhitelist[trace.Entity:GetClass()]) then
return false
end
elseif (tool == "advdupe2" and !client:GetCharacter():HasFlags("a")) then
return false
elseif (hl2Tools[tool] and !CAMI.PlayerHasAccess(client, "Helix - HL2 Tools")) then
return false
end
end

View File

@@ -0,0 +1,193 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local timer = timer
local pairs = pairs
local hook = hook
local CurTime = CurTime
local player = player
local ipairs = ipairs
local ix = ix
local IsValid = IsValid
local PLUGIN = PLUGIN
PLUGIN.disconnects = PLUGIN.disconnects or {}
PLUGIN.takeCounter = {}
timer.Create("ixBastionAntiTakeSpam", 1, 0, function()
for client, amount in pairs(PLUGIN.takeCounter) do
if (amount < 10) then continue end
if (!IsValid(client)) then continue end
for _, admin in ipairs(player.GetAll()) do
if (admin:IsSuperAdmin()) then
admin:NotifyLocalized("bastionItemTakeKick", client:Name())
end
end
client:Kick("Item take spam")
end
PLUGIN.takeCounter = {}
end)
function PLUGIN:CanPlayerInteractItem(client, action, item, data)
if (action == "take") then
if (self.takeCounter[client] and self.takeCounter[client] >= 5) then
if (self.takeCounter[client] == 5) then
for _, v in ipairs(player.GetAll()) do
if (v:IsSuperAdmin()) then
v:NotifyLocalized("bastionItemTakeWarn", client:Name())
end
end
client:NotifyLocalized("bastionTakingItemsTooQuickly")
end
self.takeCounter[client] = self.takeCounter[client] + 1
return false
end
elseif (action == "drop" and client.ixAntiItemSpam and client.ixAntiItemSpam > CurTime()) then
return false
end
end
function PLUGIN:PlayerInteractItem(client, action, item)
if (action == "take") then
self.takeCounter[client] = (self.takeCounter[client] or 0) + 1
end
end
PLUGIN.itemSpawns = {}
function PLUGIN:OnItemSpawned(entity)
if (IsValid(self.itemSpawns[entity.ixItemID])) then
if (self.itemSpawns[entity.ixItemID].ixItemID != entity.ixItemID) then
return -- just in case
end
--Now we are trying to spawn an item which already has an entity!
--Check if it is the same person, in case of weird behaviour
if (entity.ixSteamID == self.itemSpawns[entity.ixItemID]) then
local client = player.GetBySteamID(entity.ixSteamID)
if ((client.ixAntiItemSpam or 0) > CurTime()) then
for _, v in ipairs(player.GetAll()) do
if (v:IsSuperAdmin()) then
v:NotifyLocalized("bastionItemDropSpamKick", client:Name())
end
end
client:Kick("Item drop spam")
else
client.ixAntiItemSpam = CurTime() + 10
for _, v in ipairs(player.GetAll()) do
if (v:IsSuperAdmin()) then
v:NotifyLocalized("bastionItemDropSpamWarn", client:Name())
end
end
client:NotifyLocalized("bastionItemDropTooQuick")
end
end
self.itemSpawns[entity.ixItemID]:Remove()
self.itemSpawns[entity.ixItemID] = entity
else
self.itemSpawns[entity.ixItemID] = entity
end
end
function PLUGIN:CanPlayerCreateCharacter(client)
if (client.ixNextCharCreate and (client.ixNextCharCreate + ix.config.Get("charCreateInterval") * 60) > CurTime()) then
return false, "charCreateTooFast", ix.config.Get("charCreateInterval")
end
end
function PLUGIN:OnCharacterCreated(client)
if (!client:IsAdmin()) then
client.ixNextCharCreate = CurTime()
end
end
function PLUGIN:PlayerSpawnedProp(client, model, entity)
entity.ownerCharacter = client:GetName()
entity.ownerName = client:SteamName()
entity.ownerSteamID = client:SteamID()
end
function PLUGIN:OnPlayerHitGround(client, inWater, onFloater, speed)
local currentVelocity = client:GetVelocity()
client:SetVelocity(-Vector(currentVelocity.x, currentVelocity.y, 0))
end
function PLUGIN:PlayerInitialSpawn(client)
local receivers
if (!ix.config.Get("showConnectMessages", true)) then
receivers = {}
for _, ply in ipairs(player.GetAll()) do
if (ply:IsAdmin()) then
receivers[#receivers + 1] = ply
end
end
end
-- Give some time for the player's data to be loaded, just in case.
timer.Simple(1, function()
ix.chat.Send(nil, "new_connect", client:SteamName(), false, receivers)
end)
end
function PLUGIN:PlayerDisconnected(client)
local receivers
self.disconnects[client:SteamID64()] = {time = os.time(), charID = client:GetCharacter() and client:GetCharacter():GetID()}
if (!ix.config.Get("showDisconnectMessages", true)) then
receivers = {}
for _, ply in ipairs(player.GetAll()) do
if (ply:IsAdmin()) then
receivers[#receivers + 1] = ply
end
end
end
ix.chat.Send(nil, "new_disconnect", client:SteamName(), false, receivers)
end
function PLUGIN:PlayerLoadedCharacter(client, character, lastChar)
if (self.disconnects[client:SteamID64()]) then
local info = self.disconnects[client:SteamID64()]
if (info.timer) then
timer.Remove(info.timer)
if (IsValid(info.bannedBy)) then
if (info.charID) then
if (character:GetID() == info.charID) then
info.bannedBy:Notify(client:SteamName().." has reconnected and is back on their character "..character:GetName()..".")
end
else
info.bannedBy:Notify(client:SteamName().." has reconnected on a different character '"..character:GetName().."'.")
end
end
end
end
end
function PLUGIN:PlayerDeath(client, inflictor, attacker)
if (!client:GetCharacter()) then return end
ix.chat.Send(client, "bastionPlayerDeath", client:GetName() .. " (" .. client:SteamName() .. ") has died at " .. (client.ixArea and client.ixArea != "" and client.ixArea or "an Uncategorized Location") .. ".")
end
hook.Add("SAM.RanCommand", "BastionSamCommandLogs", function(client, cmd_name, args, cmd)
ix.log.Add(client, "bastionSamCommand", cmd_name, args, cmd)
end)

View File

@@ -0,0 +1,139 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local util = util
local file = file
local table = table
local timer = timer
local ipairs = ipairs
local player = player
local CAMI = CAMI
local string = string
local ents = ents
local IsValid = IsValid
local ix = ix
local PLUGIN = PLUGIN
util.AddNetworkString("ixOpenURL")
util.AddNetworkString("ixPlayerInfo")
util.AddNetworkString("ixStaffList")
util.AddNetworkString("ixPlaySound")
function PLUGIN:InitializedPlugins()
if (!CHTTP) then return end
self.API_KEY = file.Read("gamemodes/helix/plugins/bastion/apikey_proxy.txt", "GAME")
if (self.API_KEY) then
self.API_KEY = string.gsub(self.API_KEY, "[^%w%-]", "")
end
self.DISCORD_WEBHOOK_ALTS = file.Read("gamemodes/helix/plugins/bastion/apiwebhook_disocrd.txt", "GAME")
end
function PLUGIN:InitializedConfig()
ix.config.Set("EdictWarningLimit", 1024)
end
ix.util.Include("modules/sv_banlist.lua")
ix.util.Include("modules/sv_antialt.lua")
ix.util.Include("modules/sv_netsizelog.lua")
--ix.util.Include("modules/sv_netmonitor.lua") --high performance impact!
ix.log.AddType("bastionCheckInfo", function(client, target)
return string.format("%s has checked %s's info.", client:GetName(), target:GetName())
end)
ix.log.AddType("bastionSetHealth", function(client, target)
return string.format("%s has set %s's health to %d.", client:GetName(), target:GetName(), target:Health())
end)
ix.log.AddType("bastionSetArmor", function(client, target)
return string.format("%s has set %s's armor to %d.", client:GetName(), target:GetName(), target:Armor())
end)
ix.log.AddType("bastionSetName", function(client, target, oldName)
return string.format("%s has set %s's name to %s.", client:GetName(), oldName, target:GetName())
end)
ix.log.AddType("bastionSetDesc", function(client, target)
return string.format("%s has set %s's description to %s.", client:GetName(), target:GetName(), target:GetDescription())
end)
ix.log.AddType("bastionSlay", function(client, target)
return string.format("%s has slayed %s.", client:GetName(), target:GetName())
end, FLAG_DANGER)
ix.log.AddType("bastionInvSearch", function(client, name)
return string.format("%s is admin-searching %s.", client:GetName(), name)
end)
ix.log.AddType("bastionInvClose", function(client, name)
return string.format("%s has closed %s.", client:GetName(), name)
end)
ix.log.AddType("netstreamHoneypot", function(client, hook, bNoAccess)
return string.format("[BANME] %s has just hit the %s HONEYPOT!!! Please ban SteamID: %s (trigger reason: %s)", client:SteamName(), hook, client:SteamID(), bNoAccess and "no access" or "invalid arg")
end, FLAG_DANGER)
ix.log.AddType("luaHack", function(client, name)
return string.format("[BANME] %s just tried to %s through lua-injection!!! Please ban SteamID: %s", client:SteamName(), name, client:SteamID())
end)
ix.log.AddType("bastionSamCommand", function(client, cmd, args)
return string.format("%s ran SAM command '%s' with arguments: '%s'", client:Name(), cmd, table.concat(args, "' '"))
end)
ix.log.AddType("samReportClaimed", function(client, reporter)
return string.format("%s claimed a report by %s (%s).", client:Name(), reporter:Name(), reporter:SteamName())
end)
timer.Create("ixBastionEdictCheck", 60, 0, function()
local edictsCount = ents.GetEdictCount()
local edictsLeft = 8192 - edictsCount
if (edictsLeft < ix.config.Get("EdictWarningLimit")) then
if (edictsLeft < 600) then
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Basic Admin Commands")) then
v:NotifyLocalized("edictCritical", edictsLeft, edictsCount)
end
end
else
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Basic Admin Commands")) then
v:NotifyLocalized("edictWarning", edictsLeft, edictsCount)
end
end
end
end
end)
function PLUGIN:Explode(target)
local explosive = ents.Create("env_explosion")
explosive:SetPos(target:GetPos())
explosive:SetOwner(target)
explosive:Spawn()
explosive:SetKeyValue("iMagnitude", "1")
explosive:Fire("Explode", 0, 0)
explosive:EmitSound("ambient/explosions/explode_4.wav", 500, 500)
target:StopParticles()
target:Kill()
end
function PLUGIN:OpenInventory(client, target)
if (!IsValid(client) or !IsValid(target)) then return end
if (!target:IsPlayer()) then return end
local character = target:GetCharacter()
if (!character) then return end
local inventory = character:GetInventory()
if (inventory) then
local name = target:Name().."'s inventory"
ix.storage.Open(client, inventory, {
entity = target,
name = name,
OnPlayerClose = function()
ix.log.Add(client, "bastionInvClose", name)
end
})
ix.log.Add(client, "bastionInvSearch", name)
end
end